2011-09-09 Pedro Alves <pedro@codesourcery.com>
[deliverable/binutils-gdb.git] / binutils / objdump.c
index ca7741d6fc2027eb28ed83c82127a81d06579d8e..784ead27e0804d01ee44a3d654802b7f8130b842 100644 (file)
@@ -1,6 +1,6 @@
 /* objdump.c -- dump information about an object file.
    Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
 
    This file is part of GNU Binutils.
@@ -55,6 +55,7 @@
 #include "elf-bfd.h"
 #include "progress.h"
 #include "bucomm.h"
+#include "elfcomm.h"
 #include "dwarf.h"
 #include "getopt.h"
 #include "safe-ctype.h"
@@ -64,6 +65,7 @@
 #include "filenames.h"
 #include "debug.h"
 #include "budbg.h"
+#include "objdump.h"
 
 #ifdef HAVE_MMAP
 #include <sys/mman.h>
@@ -92,6 +94,7 @@ static int dump_reloc_info;           /* -r */
 static int dump_dynamic_reloc_info;    /* -R */
 static int dump_ar_hdrs;               /* -a */
 static int dump_private_headers;       /* -p */
+static char *dump_private_options;     /* -P */
 static int prefix_addresses;           /* --prefix-addresses */
 static int with_line_numbers;          /* -l */
 static bfd_boolean with_source_code;   /* -S */
@@ -109,6 +112,7 @@ static bfd_vma start_address = (bfd_vma) -1; /* --start-address */
 static bfd_vma stop_address = (bfd_vma) -1;  /* --stop-address */
 static int dump_debugging;             /* --debugging */
 static int dump_debugging_tags;                /* --debugging-tags */
+static int suppress_bfd_header;
 static int dump_special_syms = 0;      /* --special-syms */
 static bfd_vma adjust_section_vma = 0; /* --adjust-vma */
 static int file_start_context = 0;      /* --file-start-context */
@@ -183,6 +187,13 @@ static char *strtab;
 static bfd_size_type stabstr_size;
 
 static bfd_boolean is_relocatable = FALSE;
+
+/* Handlers for -P/--private.  */
+static const struct objdump_private_desc * const objdump_private_vectors[] =
+  {
+    OBJDUMP_PRIVATE_VECTORS
+    NULL
+  };
 \f
 static void
 usage (FILE *stream, int status)
@@ -194,6 +205,7 @@ usage (FILE *stream, int status)
   -a, --archive-headers    Display archive header information\n\
   -f, --file-headers       Display the contents of the overall file header\n\
   -p, --private-headers    Display object format specific file header contents\n\
+  -P, --private=OPT,OPT... Display object format specific contents\n\
   -h, --[section-]headers  Display the contents of the section headers\n\
   -x, --all-headers        Display the contents of all headers\n\
   -d, --disassemble        Display assembler contents of executable sections\n\
@@ -206,7 +218,7 @@ usage (FILE *stream, int status)
   -W[lLiaprmfFsoRt] or\n\
   --dwarf[=rawline,=decodedline,=info,=abbrev,=pubnames,=aranges,=macro,=frames,\n\
           =frames-interp,=str,=loc,=Ranges,=pubtypes,\n\
-          =trace_info,=trace_abbrev,=trace_aranges]\n\
+          =gdb_index,=trace_info,=trace_abbrev,=trace_aranges]\n\
                            Display DWARF info in the file\n\
   -t, --syms               Display the contents of the symbol table(s)\n\
   -T, --dynamic-syms       Display the contents of the dynamic symbol table\n\
@@ -219,6 +231,8 @@ usage (FILE *stream, int status)
 "));
   if (status != 2)
     {
+      const struct objdump_private_desc * const *desc;
+
       fprintf (stream, _("\n The following switches are optional:\n"));
       fprintf (stream, _("\
   -b, --target=BFDNAME           Specify the target object format as BFDNAME\n\
@@ -241,16 +255,27 @@ usage (FILE *stream, int status)
       --stop-address=ADDR        Only process data whose address is <= ADDR\n\
       --prefix-addresses         Print complete address alongside disassembly\n\
       --[no-]show-raw-insn       Display hex alongside symbolic disassembly\n\
-      --insn-width=WIDTH         Display WIDTH bytes on a signle line for -d\n\
+      --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\
       --prefix=PREFIX            Add PREFIX to absolute paths for -S\n\
-      --prefix-strip=LEVEL       Strip initial directory names for -S\n\
-\n"));
+      --prefix-strip=LEVEL       Strip initial directory names for -S\n"));
+      fprintf (stream, _("\
+      --dwarf-depth=N        Do not display DIEs at depth N or greater\n\
+      --dwarf-start=N        Display DIEs starting with N, at the same depth\n\
+                             or deeper\n\n"));
       list_supported_targets (program_name, stream);
       list_supported_architectures (program_name, stream);
 
       disassembler_usage (stream);
+
+      if (objdump_private_vectors[0] != NULL)
+        {
+          fprintf (stream,
+                   _("\nOptions supported for -P/--private switch:\n"));
+          for (desc = objdump_private_vectors; *desc != NULL; desc++)
+            (*desc)->help (stream);
+        }
     }
   if (REPORT_BUGS_TO[0] && status == 0)
     fprintf (stream, _("Report bugs to %s.\n"), REPORT_BUGS_TO);
@@ -267,7 +292,9 @@ enum option_values
     OPTION_PREFIX,
     OPTION_PREFIX_STRIP,
     OPTION_INSN_WIDTH,
-    OPTION_ADJUST_VMA
+    OPTION_ADJUST_VMA,
+    OPTION_DWARF_DEPTH,
+    OPTION_DWARF_START
   };
 
 static struct option long_options[]=
@@ -275,6 +302,7 @@ static struct option long_options[]=
   {"adjust-vma", required_argument, NULL, OPTION_ADJUST_VMA},
   {"all-headers", no_argument, NULL, 'x'},
   {"private-headers", no_argument, NULL, 'p'},
+  {"private", required_argument, NULL, 'P'},
   {"architecture", required_argument, NULL, 'm'},
   {"archive-headers", no_argument, NULL, 'a'},
   {"debugging", no_argument, NULL, 'g'},
@@ -315,6 +343,8 @@ static struct option long_options[]=
   {"prefix", required_argument, NULL, OPTION_PREFIX},
   {"prefix-strip", required_argument, NULL, OPTION_PREFIX_STRIP},
   {"insn-width", required_argument, NULL, OPTION_INSN_WIDTH},
+  {"dwarf-depth",      required_argument, 0, OPTION_DWARF_DEPTH},
+  {"dwarf-start",      required_argument, 0, OPTION_DWARF_START},
   {0, no_argument, 0, 0}
 };
 \f
@@ -393,7 +423,8 @@ free_only_list (void)
     {
       if (! at_least_one_seen)
        {
-         non_fatal (_("Section '%s' mentioned in a -j option, but not found in any input file"),
+         non_fatal (_("section '%s' mentioned in a -j option, "
+                      "but not found in any input file"),
                     only->name);
          exit_status = 1;
        }
@@ -510,8 +541,6 @@ dump_headers (bfd *abfd)
 
   if (wide_output)
     printf (_("  Flags"));
-  if (abfd->flags & HAS_LOAD_PAGE)
-    printf (_("  Pg"));
   printf ("\n");
 
   bfd_map_over_sections (abfd, dump_section_header, NULL);
@@ -555,6 +584,7 @@ slurp_dynamic_symtab (bfd *abfd)
       if (!(bfd_get_file_flags (abfd) & DYNAMIC))
        {
          non_fatal (_("%s: not a dynamic object"), bfd_get_filename (abfd));
+         exit_status = 1;
          dynsymcount = 0;
          return NULL;
        }
@@ -1210,9 +1240,6 @@ update_source_path (const char *filename)
   const char *fname;
   int i;
 
-  if (filename == NULL)
-    return NULL;
-
   p = try_print_file_open (filename, filename);
   if (p != NULL)
     return p;
@@ -1350,7 +1377,7 @@ show_line (bfd *abfd, asection *section, bfd_vma addr_offset)
       unsigned l;
 
       for (pp = &print_files; *pp != NULL; pp = &(*pp)->next)
-       if (strcmp ((*pp)->filename, filename) == 0)
+       if (filename_cmp ((*pp)->filename, filename) == 0)
          break;
       p = *pp;
 
@@ -1626,10 +1653,16 @@ disassemble_bytes (struct disassemble_info * inf,
              inf->stream = stdout;
              if (insn_width == 0 && inf->bytes_per_line != 0)
                octets_per_line = inf->bytes_per_line;
-             if (octets < 0)
+             if (octets < (int) opb)
                {
                  if (sfile.pos)
                    printf ("%s\n", sfile.buffer);
+                 if (octets >= 0)
+                   {
+                     non_fatal (_("disassemble_fn returned length %d"),
+                                octets);
+                     exit_status = 1;
+                   }
                  break;
                }
            }
@@ -2107,7 +2140,7 @@ disassemble_data (bfd *abfd)
       const bfd_arch_info_type *inf = bfd_scan_arch (machine);
 
       if (inf == NULL)
-       fatal (_("Can't use supplied machine %s"), machine);
+       fatal (_("can't use supplied machine %s"), machine);
 
       abfd->arch_info = inf;
     }
@@ -2126,7 +2159,7 @@ disassemble_data (bfd *abfd)
   aux.disassemble_fn = disassembler (abfd);
   if (!aux.disassemble_fn)
     {
-      non_fatal (_("Can't disassemble for architecture %s\n"),
+      non_fatal (_("can't disassemble for architecture %s\n"),
                 bfd_printable_arch_mach (bfd_get_arch (abfd), 0));
       exit_status = 1;
       return;
@@ -2193,20 +2226,15 @@ load_specific_debug_section (enum dwarf_section_display_enum debug,
   struct dwarf_section *section = &debug_displays [debug].section;
   bfd *abfd = (bfd *) file;
   bfd_boolean ret;
-  int section_is_compressed;
 
   /* If it is already loaded, do nothing.  */
   if (section->start != NULL)
     return 1;
 
-  section_is_compressed = section->name == section->compressed_name;
-
   section->address = 0;
   section->size = bfd_get_section_size (sec);
-  section->start = (unsigned char *) xmalloc (section->size);
-
-  ret = bfd_get_section_contents (abfd, sec, section->start, 0,
-                                 section->size);
+  section->start = NULL;
+  ret = bfd_get_full_section_contents (abfd, sec, &section->start);
 
   if (! ret)
     {
@@ -2216,18 +2244,6 @@ load_specific_debug_section (enum dwarf_section_display_enum debug,
       return 0;
     }
 
-  if (section_is_compressed)
-    {
-      bfd_size_type size = section->size;
-      if (! bfd_uncompress_section_contents (&section->start, &size))
-        {
-          free_debug_section (debug);
-          printf (_("\nCan't uncompress section '%s'.\n"), section->name);
-          return 0;
-        }
-      section->size = size;
-    }
-
   if (is_relocatable && debug_displays [debug].relocate)
     {
       /* We want to relocate the data we've already read (and
@@ -2349,10 +2365,24 @@ dump_dwarf (bfd *abfd)
   else
     abort ();
 
-  if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
+  switch (bfd_get_arch (abfd))
     {
-      const struct elf_backend_data *bed = get_elf_backend_data (abfd);
-      init_dwarf_regnames (bed->elf_machine_code);
+    case bfd_arch_i386:
+      switch (bfd_get_mach (abfd))
+       {
+       case bfd_mach_x86_64:
+       case bfd_mach_x86_64_intel_syntax:
+         init_dwarf_regnames_x86_64 ();
+         break;
+
+       default:
+         init_dwarf_regnames_i386 ();
+         break;
+       }
+      break;
+
+    default:
+      break;
     }
 
   bfd_map_over_sections (abfd, dump_dwarf_section, NULL);
@@ -2382,11 +2412,11 @@ read_section_stabs (bfd *abfd, const char *sect_name, bfd_size_type *size_ptr)
 
   if (! bfd_get_section_contents (abfd, stabsect, contents, 0, size))
     {
-      non_fatal (_("Reading %s section of %s failed: %s"),
+      non_fatal (_("reading %s section of %s failed: %s"),
                 sect_name, bfd_get_filename (abfd),
                 bfd_errmsg (bfd_get_error ()));
-      free (contents);
       exit_status = 1;
+      free (contents);
       return NULL;
     }
 
@@ -2560,7 +2590,7 @@ dump_bfd_header (bfd *abfd)
   printf (_("architecture: %s, "),
          bfd_printable_arch_mach (bfd_get_arch (abfd),
                                   bfd_get_mach (abfd)));
-  printf (_("flags 0x%08x:\n"), abfd->flags);
+  printf (_("flags 0x%08x:\n"), abfd->flags & ~BFD_FLAGS_FOR_BFD_USE_MASK);
 
 #define PF(x, y)    if (abfd->flags & x) {printf("%s%s", comma, y); comma=", ";}
   PF (HAS_RELOC, "HAS_RELOC");
@@ -2586,6 +2616,57 @@ dump_bfd_private_header (bfd *abfd)
   bfd_print_private_bfd_data (abfd, stdout);
 }
 
+static void
+dump_target_specific (bfd *abfd)
+{
+  const struct objdump_private_desc * const *desc;
+  struct objdump_private_option *opt;
+  char *e, *b;
+
+  /* Find the desc.  */
+  for (desc = objdump_private_vectors; *desc != NULL; desc++)
+    if ((*desc)->filter (abfd))
+      break;
+
+  if (desc == NULL)
+    {
+      non_fatal (_("option -P/--private not supported by this file"));
+      return;
+    }
+
+  /* Clear all options.  */
+  for (opt = (*desc)->options; opt->name; opt++)
+    opt->selected = FALSE;
+
+  /* Decode options.  */
+  b = dump_private_options;
+  do
+    {
+      e = strchr (b, ',');
+
+      if (e)
+        *e = 0;
+
+      for (opt = (*desc)->options; opt->name; opt++)
+        if (strcmp (opt->name, b) == 0)
+          {
+            opt->selected = TRUE;
+            break;
+          }
+      if (opt->name == NULL)
+        non_fatal (_("target specific dump '%s' not supported"), b);
+
+      if (e)
+        {
+          *e = ',';
+          b = e + 1;
+        }
+    }
+  while (e != NULL);
+
+  /* Dump.  */
+  (*desc)->dump (abfd);
+}
 \f
 /* Display a section in hexadecimal format with associated characters.
    Each line prefixed by the zero padded address.  */
@@ -2643,9 +2724,11 @@ dump_section (bfd *abfd, asection *section, void *dummy ATTRIBUTE_UNUSED)
            (unsigned long) (section->filepos + start_offset));
   printf ("\n");
 
-  data = (bfd_byte *) xmalloc (datasize);
-
-  bfd_get_section_contents (abfd, section, data, 0, datasize);
+  if (!bfd_get_full_section_contents (abfd, section, &data))
+    {
+      non_fatal (_("Reading section failed"));
+      return;
+    }
 
   width = 4;
 
@@ -2826,6 +2909,7 @@ dump_reloc_set (bfd *abfd, asection *sec, arelent **relpp, long relcount)
       unsigned int linenumber;
       const char *sym_name;
       const char *section_name;
+      bfd_vma addend2 = 0;
 
       if (start_address != (bfd_vma) -1
          && q->address < start_address)
@@ -2853,7 +2937,7 @@ dump_reloc_set (bfd *abfd, asection *sec, arelent **relpp, long relcount)
              && (linenumber != last_line
                  || (filename != NULL
                      && last_filename != NULL
-                     && strcmp (filename, last_filename) != 0)))
+                     && filename_cmp (filename, last_filename) != 0)))
            {
              printf ("%s:%u\n", filename == NULL ? "???" : filename, linenumber);
              last_line = linenumber;
@@ -2881,7 +2965,37 @@ dump_reloc_set (bfd *abfd, asection *sec, arelent **relpp, long relcount)
       if (q->howto == NULL)
        printf (" *unknown*         ");
       else if (q->howto->name)
-       printf (" %-16s  ", 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);
 
@@ -2901,9 +3015,19 @@ dump_reloc_set (bfd *abfd, asection *sec, arelent **relpp, long relcount)
          printf ("+0x");
          bfd_printf_vma (abfd, q->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
@@ -3035,7 +3159,7 @@ dump_bfd (bfd *abfd)
       bfd_map_over_sections (abfd, adjust_addresses, &has_reloc);
     }
 
-  if (! dump_debugging_tags)
+  if (! dump_debugging_tags && ! suppress_bfd_header)
     printf (_("\n%s:     file format %s\n"), bfd_get_filename (abfd),
            abfd->xvec->name);
   if (dump_ar_hdrs)
@@ -3044,7 +3168,9 @@ dump_bfd (bfd *abfd)
     dump_bfd_header (abfd);
   if (dump_private_headers)
     dump_bfd_private_header (abfd);
-  if (! dump_debugging_tags)
+  if (dump_private_options != NULL)
+    dump_target_specific (abfd);
+  if (! dump_debugging_tags && ! suppress_bfd_header)
     putchar ('\n');
   if (dump_section_headers)
     dump_headers (abfd);
@@ -3189,6 +3315,10 @@ display_file (char *filename, char *target)
       return;
     }
 
+  /* Decompress sections unless dumping the section contents.  */
+  if (!dump_section_contents)
+    file->flags |= BFD_DECOMPRESS;
+
   /* If the file is an archive, process all of its elements.  */
   if (bfd_check_format (file, bfd_archive))
     {
@@ -3251,7 +3381,7 @@ main (int argc, char **argv)
   set_default_bfd_target ();
 
   while ((c = getopt_long (argc, argv,
-                          "pib:m:M:VvCdDlfFaHhrRtTxsSI:j:wE:zgeGW::",
+                          "pP:ib:m:M:VvCdDlfFaHhrRtTxsSI:j:wE:zgeGW::",
                           long_options, (int *) 0))
         != EOF)
     {
@@ -3336,7 +3466,7 @@ main (int argc, char **argv)
            endian = BFD_ENDIAN_LITTLE;
          else
            {
-             non_fatal (_("unrecognized -E option"));
+             nonfatal (_("unrecognized -E option"));
              usage (stderr, 1);
            }
          break;
@@ -3348,6 +3478,7 @@ main (int argc, char **argv)
          else
            {
              non_fatal (_("unrecognized --endian type `%s'"), optarg);
+             exit_status = 1;
              usage (stderr, 1);
            }
          break;
@@ -3367,6 +3498,10 @@ main (int argc, char **argv)
          dump_private_headers = TRUE;
          seenflag = TRUE;
          break;
+       case 'P':
+         dump_private_options = optarg;
+         seenflag = TRUE;
+         break;
        case 'x':
          dump_private_headers = TRUE;
          dump_symtab = TRUE;
@@ -3427,6 +3562,19 @@ main (int argc, char **argv)
          else
            dwarf_select_sections_all ();
          break;
+       case OPTION_DWARF_DEPTH:
+         {
+           char *cp;
+           dwarf_cutoff_level = strtoul (optarg, & cp, 0);
+         }
+         break;
+       case OPTION_DWARF_START:
+         {
+           char *cp;
+           dwarf_start_die = strtoul (optarg, & cp, 0);
+           suppress_bfd_header = 1;
+         }
+         break;
        case 'G':
          dump_stab_section_info = TRUE;
          seenflag = TRUE;
This page took 0.043233 seconds and 4 git commands to generate.