Move the last entry to proper ChangeLog.
[deliverable/binutils-gdb.git] / binutils / readelf.c
index f1f849fa2a468ec45306c9a10ac16cc270baf2d3..2c74411675108662d20f560ab3582f76f0da92db 100644 (file)
@@ -1,5 +1,5 @@
 /* readelf.c -- display contents of an ELF format file
-   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
    Free Software Foundation, Inc.
 
    Originally developed by Eric Youngdale <eric@andante.jic.com>
@@ -9,7 +9,7 @@
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
   ELF file than is provided by objdump.  In particular it can display DWARF
   debugging information which (at the moment) objdump cannot.  */
 \f
+#include "sysdep.h"
 #include <assert.h>
-#include <sys/types.h>
 #include <sys/stat.h>
-#include <stdio.h>
 #include <time.h>
 
 /* for PATH_MAX */
 #define BFD64
 #endif
 
+#include "bfd.h"
+#include "bucomm.h"
 #include "dwarf.h"
 
 #include "elf/common.h"
 #include "elf/external.h"
 #include "elf/internal.h"
 
+
+/* Included here, before RELOC_MACROS_GEN_FUNC is defined, so that
+   we can obtain the H8 reloc numbers.  We need these for the
+   get_reloc_size() function.  We include h8.h again after defining
+   RELOC_MACROS_GEN_FUNC so that we get the naming function as well.  */
+
+#include "elf/h8.h"
+#undef _ELF_H8_H
+
+/* Undo the effects of #including reloc-macros.h.  */
+
+#undef START_RELOC_NUMBERS
+#undef RELOC_NUMBER
+#undef FAKE_RELOC
+#undef EMPTY_RELOC
+#undef END_RELOC_NUMBERS
+#undef _RELOC_MACROS_H
+
 /* The following headers use the elf/reloc-macros.h file to
    automatically generate relocation recognition functions
    such as elf_mips_reloc_type()  */
 #include "elf/arm.h"
 #include "elf/avr.h"
 #include "elf/bfin.h"
+#include "elf/cr16.h"
 #include "elf/cris.h"
 #include "elf/crx.h"
 #include "elf/d10v.h"
 
 #include "aout/ar.h"
 
-#include "bucomm.h"
 #include "getopt.h"
 #include "libiberty.h"
+#include "safe-ctype.h"
 
 char *program_name = "readelf";
 static long archive_file_offset;
@@ -200,33 +220,37 @@ static size_t group_count;
 static struct group *section_groups;
 static struct group **section_headers_groups;
 
-/* A linked list of the section names for which dumps were requested
-   by name.  */
+
+/* Flag bits indicating particular types of dump.  */
+#define HEX_DUMP       (1 << 0)        /* The -x command line switch.  */
+#define DISASS_DUMP    (1 << 1)        /* The -i command line switch.  */
+#define DEBUG_DUMP     (1 << 2)        /* The -w command line switch.  */
+#define STRING_DUMP     (1 << 3)       /* The -p command line switch.  */
+
+typedef unsigned char dump_type;
+
+/* A linked list of the section names for which dumps were requested.  */
 struct dump_list_entry
 {
   char *name;
-  int type;
+  dump_type type;
   struct dump_list_entry *next;
 };
 static struct dump_list_entry *dump_sects_byname;
 
-/* A dynamic array of flags indicating for which sections a hex dump
-   has been requested (via the -x switch) and/or a disassembly dump
-   (via the -i switch).  */
-char *cmdline_dump_sects = NULL;
-unsigned num_cmdline_dump_sects = 0;
+/* A dynamic array of flags indicating for which sections a dump
+   has been requested via command line switches.  */
+static dump_type *   cmdline_dump_sects = NULL;
+static unsigned int  num_cmdline_dump_sects = 0;
 
 /* A dynamic array of flags indicating for which sections a dump of
    some kind has been requested.  It is reset on a per-object file
    basis and then initialised from the cmdline_dump_sects array,
    the results of interpreting the -w switch, and the
    dump_sects_byname list.  */
-char *dump_sects = NULL;
-unsigned int num_dump_sects = 0;
+static dump_type *   dump_sects = NULL;
+static unsigned int  num_dump_sects = 0;
 
-#define HEX_DUMP       (1 << 0)
-#define DISASS_DUMP    (1 << 1)
-#define DEBUG_DUMP     (1 << 2)
 
 /* How to print a vma value.  */
 typedef enum print_mode
@@ -271,8 +295,6 @@ static void (*byte_put) (unsigned char *, bfd_vma, int);
 
 #define BYTE_GET(field)        byte_get (field, sizeof (field))
 
-#define NUM_ELEM(array)        (sizeof (array) / sizeof ((array)[0]))
-
 #define GET_ELF_SYMBOLS(file, section)                 \
   (is_32bit_elf ? get_32bit_elf_symbols (file, section)        \
    : get_64bit_elf_symbols (file, section))
@@ -283,8 +305,8 @@ static void (*byte_put) (unsigned char *, bfd_vma, int);
 #define GET_DYNAMIC_NAME(offset)       (dynamic_strings + offset)
 
 /* This is just a bit of syntatic sugar.  */
-#define streq(a,b)     (strcmp ((a), (b)) == 0)
-#define strneq(a,b,n)  (strncmp ((a), (b), (n)) == 0)
+#define streq(a,b)       (strcmp ((a), (b)) == 0)
+#define strneq(a,b,n)    (strncmp ((a), (b), (n)) == 0)
 #define const_strneq(a,b) (strncmp ((a), (b), sizeof (b) - 1) == 0)
 \f
 static void *
@@ -599,6 +621,7 @@ guess_is_rela (unsigned long e_machine)
     case EM_AVR:
     case EM_AVR_OLD:
     case EM_BLACKFIN:
+    case EM_CR16:
     case EM_CRIS:
     case EM_CRX:
     case EM_D30V:
@@ -693,7 +716,7 @@ slurp_rela_relocs (FILE *file,
       if (relas == NULL)
        {
          free (erelas);
-         error (_("out of memory parsing relocs"));
+         error (_("out of memory parsing relocs\n"));
          return 0;
        }
 
@@ -721,7 +744,7 @@ slurp_rela_relocs (FILE *file,
       if (relas == NULL)
        {
          free (erelas);
-         error (_("out of memory parsing relocs"));
+         error (_("out of memory parsing relocs\n"));
          return 0;
        }
 
@@ -765,7 +788,7 @@ slurp_rel_relocs (FILE *file,
       if (rels == NULL)
        {
          free (erels);
-         error (_("out of memory parsing relocs"));
+         error (_("out of memory parsing relocs\n"));
          return 0;
        }
 
@@ -793,7 +816,7 @@ slurp_rel_relocs (FILE *file,
       if (rels == NULL)
        {
          free (erels);
-         error (_("out of memory parsing relocs"));
+         error (_("out of memory parsing relocs\n"));
          return 0;
        }
 
@@ -1173,6 +1196,10 @@ dump_relocations (FILE *file,
        case EM_CYGNUS_MEP:
          rtype = elf_mep_reloc_type (type);
          break;
+
+       case EM_CR16:
+         rtype = elf_cr16_reloc_type (type);
+         break;
        }
 
       if (rtype == NULL)
@@ -1769,8 +1796,9 @@ get_machine_name (unsigned e_machine)
     case EM_ALTERA_NIOS2:      return "Altera Nios II";
     case EM_XC16X:             return "Infineon Technologies xc16x";
     case EM_CYGNUS_MEP:         return "Toshiba MeP Media Engine";
+    case EM_CR16:              return "National Semiconductor's CR16";
     default:
-      snprintf (buff, sizeof (buff), _("<unknown>: %x"), e_machine);
+      snprintf (buff, sizeof (buff), _("<unknown>: 0x%x"), e_machine);
       return buff;
     }
 }
@@ -2722,9 +2750,10 @@ static struct option options[] =
   {"arch-specific",    no_argument, 0, 'A'},
   {"version-info",     no_argument, 0, 'V'},
   {"use-dynamic",      no_argument, 0, 'D'},
+  {"unwind",          no_argument, 0, 'u'},
   {"hex-dump",        required_argument, 0, 'x'},
   {"debug-dump",       optional_argument, 0, OPTION_DEBUG_DUMP},
-  {"unwind",          no_argument, 0, 'u'},
+  {"string-dump",      required_argument, 0, 'p'},
 #ifdef SUPPORT_DISASSEMBLY
   {"instruction-dump", required_argument, 0, 'i'},
 #endif
@@ -2736,11 +2765,11 @@ static struct option options[] =
 };
 
 static void
-usage (void)
+usage (FILE *stream)
 {
-  fprintf (stdout, _("Usage: readelf <option(s)> elf-file(s)\n"));
-  fprintf (stdout, _(" Display information about the contents of ELF format files\n"));
-  fprintf (stdout, _(" Options are:\n\
+  fprintf (stream, _("Usage: readelf <option(s)> elf-file(s)\n"));
+  fprintf (stream, _(" Display information about the contents of ELF format files\n"));
+  fprintf (stream, _(" Options are:\n\
   -a --all               Equivalent to: -h -l -S -s -r -d -V -A -I\n\
   -h --file-header       Display the ELF file header\n\
   -l --program-headers   Display the program headers\n\
@@ -2759,24 +2788,29 @@ usage (void)
   -V --version-info      Display the version sections (if present)\n\
   -A --arch-specific     Display architecture specific information (if any).\n\
   -D --use-dynamic       Use the dynamic section info when displaying symbols\n\
-  -x --hex-dump=<number> Dump the contents of section <number>\n\
+  -x --hex-dump=<number|name>\n\
+                         Dump the contents of section <number|name> as bytes\n\
+  -p --string-dump=<number|name>\n\
+                         Dump the contents of section <number|name> as strings\n\
   -w[liaprmfFsoR] or\n\
   --debug-dump[=line,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=str,=loc,=Ranges]\n\
                          Display the contents of DWARF2 debug sections\n"));
 #ifdef SUPPORT_DISASSEMBLY
-  fprintf (stdout, _("\
-  -i --instruction-dump=<number>\n\
-                         Disassemble the contents of section <number>\n"));
+  fprintf (stream, _("\
+  -i --instruction-dump=<number|name>\n\
+                         Disassemble the contents of section <number|name>\n"));
 #endif
-  fprintf (stdout, _("\
+  fprintf (stream, _("\
   -I --histogram         Display histogram of bucket list lengths\n\
   -W --wide              Allow output width to exceed 80 characters\n\
   @<file>                Read options from <file>\n\
   -H --help              Display this information\n\
   -v --version           Display the version number of readelf\n"));
-  fprintf (stdout, _("Report bugs to %s\n"), REPORT_BUGS_TO);
 
-  exit (0);
+  if (REPORT_BUGS_TO[0] && stream == stdout)
+    fprintf (stdout, _("Report bugs to %s\n"), REPORT_BUGS_TO);
+
+  exit (stream == stdout ? 0 : 1);
 }
 
 /* Record the fact that the user wants the contents of section number
@@ -2785,20 +2819,20 @@ usage (void)
    the first time.  */
 
 static void
-request_dump (unsigned int section, int type)
+request_dump_bynumber (unsigned int section, dump_type type)
 {
   if (section >= num_dump_sects)
     {
-      char *new_dump_sects;
+      dump_type *new_dump_sects;
 
-      new_dump_sects = calloc (section + 1, 1);
+      new_dump_sects = calloc (section + 1, sizeof (* dump_sects));
 
       if (new_dump_sects == NULL)
-       error (_("Out of memory allocating dump request table."));
+       error (_("Out of memory allocating dump request table.\n"));
       else
        {
          /* Copy current flag settings.  */
-         memcpy (new_dump_sects, dump_sects, num_dump_sects);
+         memcpy (new_dump_sects, dump_sects, num_dump_sects * sizeof (* dump_sects));
 
          free (dump_sects);
 
@@ -2816,17 +2850,17 @@ request_dump (unsigned int section, int type)
 /* Request a dump by section name.  */
 
 static void
-request_dump_byname (const char *section, int type)
+request_dump_byname (const char *section, dump_type type)
 {
   struct dump_list_entry *new_request;
 
   new_request = malloc (sizeof (struct dump_list_entry));
   if (!new_request)
-    error (_("Out of memory allocating dump request table."));
+    error (_("Out of memory allocating dump request table.\n"));
 
   new_request->name = strdup (section);
   if (!new_request->name)
-    error (_("Out of memory allocating dump request table."));
+    error (_("Out of memory allocating dump request table.\n"));
 
   new_request->type = type;
 
@@ -2840,10 +2874,10 @@ parse_args (int argc, char **argv)
   int c;
 
   if (argc < 2)
-    usage ();
+    usage (stderr);
 
   while ((c = getopt_long
-         (argc, argv, "ersuahnldSDAINtgw::x:i:vVWH", options, NULL)) != EOF)
+         (argc, argv, "ersuahnldSDAINtgw::x:i:vVWHp:", options, NULL)) != EOF)
     {
       char *cp;
       int section;
@@ -2854,7 +2888,7 @@ parse_args (int argc, char **argv)
          /* Long options.  */
          break;
        case 'H':
-         usage ();
+         usage (stdout);
          break;
 
        case 'a':
@@ -2921,10 +2955,18 @@ parse_args (int argc, char **argv)
          do_dump++;
          section = strtoul (optarg, & cp, 0);
          if (! *cp && section >= 0)
-           request_dump (section, HEX_DUMP);
+           request_dump_bynumber (section, HEX_DUMP);
          else
            request_dump_byname (optarg, HEX_DUMP);
          break;
+       case 'p':
+         do_dump++;
+         section = strtoul (optarg, & cp, 0);
+         if (! *cp && section >= 0)
+           request_dump_bynumber (section, STRING_DUMP);
+         else
+           request_dump_byname (optarg, STRING_DUMP);
+         break;
        case 'w':
          do_dump++;
          if (optarg == 0)
@@ -3072,11 +3114,9 @@ parse_args (int argc, char **argv)
          do_dump++;
          section = strtoul (optarg, & cp, 0);
          if (! *cp && section >= 0)
-           {
-             request_dump (section, DISASS_DUMP);
-             break;
-           }
-         goto oops;
+           request_dump_bynumber (section, DISASS_DUMP);
+         else
+           request_dump_byname (optarg, DISASS_DUMP);
 #endif
        case 'v':
          print_version (program_name);
@@ -3088,14 +3128,11 @@ parse_args (int argc, char **argv)
          do_wide++;
          break;
        default:
-#ifdef SUPPORT_DISASSEMBLY
-       oops:
-#endif
          /* xgettext:c-format */
          error (_("Invalid option '-%c'\n"), c);
          /* Drop through.  */
        case '?':
-         usage ();
+         usage (stderr);
        }
     }
 
@@ -3103,11 +3140,11 @@ parse_args (int argc, char **argv)
       && !do_segments && !do_header && !do_dump && !do_version
       && !do_histogram && !do_debugging && !do_arch && !do_notes
       && !do_section_groups)
-    usage ();
+    usage (stderr);
   else if (argc < 3)
     {
       warn (_("Nothing to do.\n"));
-      usage ();
+      usage (stderr);
     }
 }
 
@@ -3492,18 +3529,21 @@ process_program_headers (FILE *file)
              sec = find_section (".dynamic");
              if (sec == NULL || sec->sh_size == 0)
                {
-                 error (_("no .dynamic section in the dynamic segment"));
+                 error (_("no .dynamic section in the dynamic segment\n"));
                  break;
                }
 
+             if (sec->sh_type == SHT_NOBITS)
+               break;
+
              dynamic_addr = sec->sh_offset;
              dynamic_size = sec->sh_size;
 
              if (dynamic_addr < segment->p_offset
                  || dynamic_addr > segment->p_offset + segment->p_filesz)
-               warn (_("the .dynamic section is not contained within the dynamic segment"));
+               warn (_("the .dynamic section is not contained within the dynamic segment\n"));
              else if (dynamic_addr > segment->p_offset)
-               warn (_("the .dynamic section is not the first section in the dynamic segment."));
+               warn (_("the .dynamic section is not the first section in the dynamic segment.\n"));
            }
          else
            {
@@ -3524,7 +3564,7 @@ process_program_headers (FILE *file)
              int ret = snprintf (fmt, sizeof (fmt), "%%%ds", PATH_MAX);
 
              if (ret >= (int) sizeof (fmt) || ret < 0)
-               error (_("Internal error: failed to create format string to display program interpreter"));
+               error (_("Internal error: failed to create format string to display program interpreter\n"));
 
              program_interpreter[0] = 0;
              if (fscanf (file, fmt, program_interpreter) <= 0)
@@ -4154,14 +4194,14 @@ process_section_headers (FILE *file)
              || (do_debug_str      && streq (name, "str"))
              || (do_debug_loc      && streq (name, "loc"))
              )
-           request_dump (i, DEBUG_DUMP);
+           request_dump_bynumber (i, DEBUG_DUMP);
        }
       /* linkonce section to be combined with .debug_info at link time.  */
       else if ((do_debugging || do_debug_info)
               && const_strneq (name, ".gnu.linkonce.wi."))
-       request_dump (i, DEBUG_DUMP);
+       request_dump_bynumber (i, DEBUG_DUMP);
       else if (do_debug_frames && streq (name, ".eh_frame"))
-       request_dump (i, DEBUG_DUMP);
+       request_dump_bynumber (i, DEBUG_DUMP);
     }
 
   if (! do_sections)
@@ -5545,7 +5585,7 @@ dynamic_section_mips_val (Elf_Internal_Dyn *entry)
          };
          unsigned int cnt;
          int first = 1;
-         for (cnt = 0; cnt < NUM_ELEM (opts); ++cnt)
+         for (cnt = 0; cnt < ARRAY_SIZE (opts); ++cnt)
            if (entry->d_un.d_val & (1 << cnt))
              {
                printf ("%s%s", first ? "" : " ", opts[cnt]);
@@ -5634,7 +5674,7 @@ dynamic_section_parisc_val (Elf_Internal_Dyn *entry)
        size_t cnt;
        bfd_vma val = entry->d_un.d_val;
 
-       for (cnt = 0; cnt < sizeof (flags) / sizeof (flags[0]); ++cnt)
+       for (cnt = 0; cnt < ARRAY_SIZE (flags); ++cnt)
          if (val & flags[cnt].bit)
            {
              if (! first)
@@ -5845,7 +5885,7 @@ process_dynamic_section (FILE *file)
          else
            {
              if (fseek (file, 0, SEEK_END))
-               error (_("Unable to seek to end of file!"));
+               error (_("Unable to seek to end of file!\n"));
 
              section.sh_size = ftell (file) - section.sh_offset;
            }
@@ -6414,6 +6454,7 @@ process_version_sections (FILE *file)
            Elf_External_Verdef *edefs;
            unsigned int idx;
            unsigned int cnt;
+           char *endbuf;
 
            found = 1;
 
@@ -6433,6 +6474,7 @@ process_version_sections (FILE *file)
            edefs = get_data (NULL, file, section->sh_offset, 1,
                              section->sh_size,
                              _("version definition section"));
+           endbuf = (char *) edefs + section->sh_size;
            if (!edefs)
              break;
 
@@ -6447,6 +6489,8 @@ process_version_sections (FILE *file)
                int isum;
 
                vstart = ((char *) edefs) + idx;
+               if (vstart + sizeof (*edef) > endbuf)
+                 break;
 
                edef = (Elf_External_Verdef *) vstart;
 
@@ -6484,6 +6528,8 @@ process_version_sections (FILE *file)
                    vstart += aux.vda_next;
 
                    eaux = (Elf_External_Verdaux *) vstart;
+                   if (vstart + sizeof (*eaux) > endbuf)
+                     break;
 
                    aux.vda_name = BYTE_GET (eaux->vda_name);
                    aux.vda_next = BYTE_GET (eaux->vda_next);
@@ -6495,9 +6541,13 @@ process_version_sections (FILE *file)
                      printf (_("  %#06x: Parent %d, name index: %ld\n"),
                              isum, j, aux.vda_name);
                  }
+               if (j < ent.vd_cnt)
+                 printf (_("  Version def aux past end of section\n"));
 
                idx += ent.vd_next;
              }
+           if (cnt < section->sh_info)
+             printf (_("  Version definition past end of section\n"));
 
            free (edefs);
          }
@@ -6508,6 +6558,7 @@ process_version_sections (FILE *file)
            Elf_External_Verneed *eneed;
            unsigned int idx;
            unsigned int cnt;
+           char *endbuf;
 
            found = 1;
 
@@ -6526,6 +6577,7 @@ process_version_sections (FILE *file)
            eneed = get_data (NULL, file, section->sh_offset, 1,
                              section->sh_size,
                              _("version need section"));
+           endbuf = (char *) eneed + section->sh_size;
            if (!eneed)
              break;
 
@@ -6538,6 +6590,8 @@ process_version_sections (FILE *file)
                char *vstart;
 
                vstart = ((char *) eneed) + idx;
+               if (vstart + sizeof (*entry) > endbuf)
+                 break;
 
                entry = (Elf_External_Verneed *) vstart;
 
@@ -6563,6 +6617,8 @@ process_version_sections (FILE *file)
                    Elf_External_Vernaux *eaux;
                    Elf_Internal_Vernaux aux;
 
+                   if (vstart + sizeof (*eaux) > endbuf)
+                     break;
                    eaux = (Elf_External_Vernaux *) vstart;
 
                    aux.vna_hash  = BYTE_GET (eaux->vna_hash);
@@ -6584,9 +6640,13 @@ process_version_sections (FILE *file)
                    isum   += aux.vna_next;
                    vstart += aux.vna_next;
                  }
+               if (j < ent.vn_cnt)
+                 printf (_("  Version need aux past end of section\n"));
 
                idx += ent.vn_next;
              }
+           if (cnt < section->sh_info)
+             printf (_("  Version need past end of section\n"));
 
            free (eneed);
          }
@@ -6731,7 +6791,10 @@ process_version_sections (FILE *file)
                                {
                                  ivna.vna_name = BYTE_GET (evna.vna_name);
 
-                                 name = strtab + ivna.vna_name;
+                                 if (ivna.vna_name >= string_sec->sh_size)
+                                   name = _("*invalid*");
+                                 else
+                                   name = strtab + ivna.vna_name;
                                  nn += printf ("(%s%-*s",
                                                name,
                                                12 - (int) strlen (name),
@@ -6783,7 +6846,10 @@ process_version_sections (FILE *file)
 
                              ivda.vda_name = BYTE_GET (evda.vda_name);
 
-                             name = strtab + ivda.vda_name;
+                             if (ivda.vda_name >= string_sec->sh_size)
+                               name = _("*invalid*");
+                             else
+                               name = strtab + ivda.vda_name;
                              nn += printf ("(%s%-*s",
                                            name,
                                            12 - (int) strlen (name),
@@ -7043,7 +7109,7 @@ process_symbol_table (FILE *file)
                                     sizeof nb + sizeof nc)),
                 SEEK_SET))
        {
-         error (_("Unable to seek to start of dynamic information"));
+         error (_("Unable to seek to start of dynamic information\n"));
          return 0;
        }
 
@@ -7269,7 +7335,7 @@ process_symbol_table (FILE *file)
                              check_def = 0;
                            }
                          else if (! is_nobits)
-                           error (_("bad dynamic symbol"));
+                           error (_("bad dynamic symbol\n"));
                          else
                            check_def = 1;
                        }
@@ -7352,7 +7418,7 @@ process_symbol_table (FILE *file)
       lengths = calloc (nbuckets, sizeof (*lengths));
       if (lengths == NULL)
        {
-         error (_("Out of memory"));
+         error (_("Out of memory\n"));
          return 0;
        }
       for (hn = 0; hn < nbuckets; ++hn)
@@ -7368,7 +7434,7 @@ process_symbol_table (FILE *file)
       counts = calloc (maxlength + 1, sizeof (*counts));
       if (counts == NULL)
        {
-         error (_("Out of memory"));
+         error (_("Out of memory\n"));
          return 0;
        }
 
@@ -7417,7 +7483,7 @@ process_symbol_table (FILE *file)
                                     sizeof nb)),
                 SEEK_SET))
        {
-         error (_("Unable to seek to start of dynamic information"));
+         error (_("Unable to seek to start of dynamic information\n"));
          return 0;
        }
 
@@ -7441,7 +7507,7 @@ process_symbol_table (FILE *file)
                  + offset_from_vma (file, buckets_vma, 4)),
                 SEEK_SET))
        {
-         error (_("Unable to seek to start of dynamic information"));
+         error (_("Unable to seek to start of dynamic information\n"));
          return 0;
        }
 
@@ -7471,7 +7537,7 @@ process_symbol_table (FILE *file)
                                           + 4 * (ngnubuckets + maxchain), 4)),
                 SEEK_SET))
        {
-         error (_("Unable to seek to start of dynamic information"));
+         error (_("Unable to seek to start of dynamic information\n"));
          return 0;
        }
 
@@ -7495,7 +7561,7 @@ process_symbol_table (FILE *file)
                  + offset_from_vma (file, buckets_vma + 4 * ngnubuckets, 4)),
                 SEEK_SET))
        {
-         error (_("Unable to seek to start of dynamic information"));
+         error (_("Unable to seek to start of dynamic information\n"));
          return 0;
        }
 
@@ -7507,7 +7573,7 @@ process_symbol_table (FILE *file)
       lengths = calloc (ngnubuckets, sizeof (*lengths));
       if (lengths == NULL)
        {
-         error (_("Out of memory"));
+         error (_("Out of memory\n"));
          return 0;
        }
 
@@ -7532,7 +7598,7 @@ process_symbol_table (FILE *file)
       counts = calloc (maxlength + 1, sizeof (*counts));
       if (counts == NULL)
        {
-         error (_("Out of memory"));
+         error (_("Out of memory\n"));
          return 0;
        }
 
@@ -7642,8 +7708,86 @@ disassemble_section (Elf_Internal_Shdr *section, FILE *file)
 #endif
 
 static int
-dump_section (Elf_Internal_Shdr *section, FILE *file)
+dump_section_as_strings (Elf_Internal_Shdr *section, FILE *file)
 {
+  Elf_Internal_Shdr *relsec;
+  bfd_size_type num_bytes;
+  bfd_vma addr;
+  char *data;
+  char *end;
+  char *start;
+  char *name = SECTION_NAME (section);
+  bfd_boolean some_strings_shown;
+
+  num_bytes = section->sh_size;
+
+  if (num_bytes == 0 || section->sh_type == SHT_NOBITS)
+    {
+      printf (_("\nSection '%s' has no data to dump.\n"), name);
+      return 0;
+    }
+
+  addr = section->sh_addr;
+
+  start = get_data (NULL, file, section->sh_offset, 1, num_bytes,
+                   _("section data"));
+  if (!start)
+    return 0;
+
+  printf (_("\nString dump of section '%s':\n"), name);
+
+  /* If the section being dumped has relocations against it the user might
+     be expecting these relocations to have been applied.  Check for this
+     case and issue a warning message in order to avoid confusion.
+     FIXME: Maybe we ought to have an option that dumps a section with
+     relocs applied ?  */
+  for (relsec = section_headers;
+       relsec < section_headers + elf_header.e_shnum;
+       ++relsec)
+    {
+      if ((relsec->sh_type != SHT_RELA && relsec->sh_type != SHT_REL)
+         || SECTION_HEADER_INDEX (relsec->sh_info) >= elf_header.e_shnum
+         || SECTION_HEADER (relsec->sh_info) != section
+         || relsec->sh_size == 0
+         || SECTION_HEADER_INDEX (relsec->sh_link) >= elf_header.e_shnum)
+       continue;
+
+      printf (_("  Note: This section has relocations against it, but these have NOT been applied to this dump.\n"));
+      break;
+    }
+
+  data = start;
+  end  = start + num_bytes;
+  some_strings_shown = FALSE;
+
+  while (data < end)
+    {
+      while (!ISPRINT (* data))
+       if (++ data >= end)
+         break;
+
+      if (data < end)
+       {
+         printf ("  [%6zx]  %s\n", data - start, data);
+         data += strlen (data);
+         some_strings_shown = TRUE;
+       }
+    }
+
+  if (! some_strings_shown)
+    printf (_("  No strings found in this section."));
+
+  free (start);
+
+  putchar ('\n');
+  return 1;
+}
+
+
+static int
+dump_section_as_bytes (Elf_Internal_Shdr *section, FILE *file)
+{
+  Elf_Internal_Shdr *relsec;
   bfd_size_type bytes;
   bfd_vma addr;
   unsigned char *data;
@@ -7667,6 +7811,26 @@ dump_section (Elf_Internal_Shdr *section, FILE *file)
   if (!start)
     return 0;
 
+  /* If the section being dumped has relocations against it the user might
+     be expecting these relocations to have been applied.  Check for this
+     case and issue a warning message in order to avoid confusion.
+     FIXME: Maybe we ought to have an option that dumps a section with
+     relocs applied ?  */
+  for (relsec = section_headers;
+       relsec < section_headers + elf_header.e_shnum;
+       ++relsec)
+    {
+      if ((relsec->sh_type != SHT_RELA && relsec->sh_type != SHT_REL)
+         || SECTION_HEADER_INDEX (relsec->sh_info) >= elf_header.e_shnum
+         || SECTION_HEADER (relsec->sh_info) != section
+         || relsec->sh_size == 0
+         || SECTION_HEADER_INDEX (relsec->sh_link) >= elf_header.e_shnum)
+       continue;
+
+      printf (_(" NOTE: This section has relocations against it, but these have NOT been applied to this dump.\n"));
+      break;
+    }
+
   data = start;
 
   while (bytes)
@@ -7708,9 +7872,47 @@ dump_section (Elf_Internal_Shdr *section, FILE *file)
 
   free (start);
 
+  putchar ('\n');
   return 1;
 }
 
+/* Return the number of bytes affected by a given reloc.
+   This information is architecture and reloc dependent.
+   Returns 4 by default, although this is not always correct.
+   It should return 0 if a decision cannot be made.
+   FIXME: This is not the correct way to solve this problem.
+   The proper way is to have target specific reloc sizing functions
+   created by the reloc-macros.h header, in the same way that it
+   already creates the reloc naming functions.  */
+
+static unsigned int
+get_reloc_size (Elf_Internal_Rela * reloc)
+{
+  switch (elf_header.e_machine)
+    {
+    case EM_H8S:
+    case EM_H8_300:
+    case EM_H8_300H:
+    case EM_H8_500:
+      switch (ELF32_R_TYPE (reloc->r_info))
+       {
+         /* PR gas/3800 - without this information we do not correctly
+            decode the debug information generated by the h8300 assembler.  */
+       case R_H8_DIR16:
+         return 2;
+       default:
+         return 4;
+       }
+    default:
+      /* FIXME: We need to extend this switch statement to cope with other
+        architecture's relocs.  (When those relocs are used against debug
+        sections, and when their size is not 4).  But see the multiple
+        inclusions of <elf/h8.h> for an example of the hoops that we need
+        to jump through in order to obtain the reloc numbers.  */
+      return 4;
+    }
+}
+
 /* Apply addends of RELA relocations.  */
 
 static int
@@ -7720,14 +7922,13 @@ debug_apply_rela_addends (void *file,
 {
   Elf_Internal_Shdr *relsec;
   unsigned char *end = start + section->sh_size;
-  /* FIXME: The relocation field size is relocation type dependent.  */
-  unsigned int reloc_size = 4;
 
   if (!is_relocatable)
     return 1;
 
-  if (section->sh_size < reloc_size)
-    return 1;
+  /* SH uses RELA but uses in place value instead of the addend field.  */
+  if (elf_header.e_machine == EM_SH)
+    return 0;
 
   for (relsec = section_headers;
        relsec < section_headers + elf_header.e_shnum;
@@ -7756,6 +7957,16 @@ debug_apply_rela_addends (void *file,
       for (rp = rela; rp < rela + nrelas; ++rp)
        {
          unsigned char *loc;
+         unsigned int reloc_size;
+
+         reloc_size = get_reloc_size (rp);
+         if (reloc_size == 0)
+           {
+             warn (_("skipping relocation of unknown size against offset 0x%lx in section %s\n"),
+                   (unsigned long) rp->r_offset,
+                   SECTION_NAME (section));
+             continue;
+           }
 
          loc = start + rp->r_offset;
          if ((loc + reloc_size) > end)
@@ -7927,7 +8138,7 @@ initialise_dumps_byname (void)
       for (i = 0, any = 0; i < elf_header.e_shnum; i++)
        if (streq (SECTION_NAME (section_headers + i), cur->name))
          {
-           request_dump (i, cur->type);
+           request_dump_bynumber (i, cur->type);
            any = 1;
          }
 
@@ -7957,10 +8168,13 @@ process_section_contents (FILE *file)
        disassemble_section (section, file);
 #endif
       if (dump_sects[i] & HEX_DUMP)
-       dump_section (section, file);
+       dump_section_as_bytes (section, file);
 
       if (dump_sects[i] & DEBUG_DUMP)
        display_debug_section (section, file);
+
+      if (dump_sects[i] & STRING_DUMP)
+       dump_section_as_strings (section, file);
     }
 
   /* Check to see if the user requested a
@@ -8206,8 +8420,166 @@ display_arm_attribute (unsigned char *p)
   return p;
 }
 
+static unsigned char *
+display_gnu_attribute (unsigned char * p,
+                      unsigned char * (* display_proc_gnu_attribute) (unsigned char *, int))
+{
+  int tag;
+  unsigned int len;
+  int val;
+  int type;
+
+  tag = read_uleb128 (p, &len);
+  p += len;
+
+  /* Tag_compatibility is the only generic GNU attribute defined at
+     present.  */
+  if (tag == 32)
+    {
+      val = read_uleb128 (p, &len);
+      p += len;
+      printf ("flag = %d, vendor = %s\n", val, p);
+      p += strlen ((char *) p) + 1;
+      return p;
+    }
+
+  if ((tag & 2) == 0 && display_proc_gnu_attribute)
+    return display_proc_gnu_attribute (p, tag);
+
+  if (tag & 1)
+    type = 1; /* String.  */
+  else
+    type = 2; /* uleb128.  */
+  printf ("  Tag_unknown_%d: ", tag);
+
+  if (type == 1)
+    {
+      printf ("\"%s\"\n", p);
+      p += strlen ((char *) p) + 1;
+    }
+  else
+    {
+      val = read_uleb128 (p, &len);
+      p += len;
+      printf ("%d (0x%x)\n", val, val);
+    }
+
+  return p;
+}
+
+static unsigned char *
+display_power_gnu_attribute (unsigned char *p, int tag)
+{
+  int type;
+  unsigned int len;
+  int val;
+
+  if (tag == Tag_GNU_Power_ABI_FP)
+    {
+      val = read_uleb128 (p, &len);
+      p += len;
+      printf ("  Tag_GNU_Power_ABI_FP: ");
+
+      switch (val)
+       {
+       case 0:
+         printf ("Hard or soft float\n");
+         break;
+       case 1:
+         printf ("Hard float\n");
+         break;
+       case 2:
+         printf ("Soft float\n");
+         break;
+       default:
+         printf ("??? (%d)\n", val);
+         break;
+       }
+      return p;
+   }
+
+  if (tag & 1)
+    type = 1; /* String.  */
+  else
+    type = 2; /* uleb128.  */
+  printf ("  Tag_unknown_%d: ", tag);
+
+  if (type == 1)
+    {
+      printf ("\"%s\"\n", p);
+      p += strlen ((char *) p) + 1;
+    }
+  else
+    {
+      val = read_uleb128 (p, &len);
+      p += len;
+      printf ("%d (0x%x)\n", val, val);
+    }
+
+  return p;
+}
+
+static unsigned char *
+display_mips_gnu_attribute (unsigned char *p, int tag)
+{
+  int type;
+  unsigned int len;
+  int val;
+
+  if (tag == Tag_GNU_MIPS_ABI_FP)
+    {
+      val = read_uleb128 (p, &len);
+      p += len;
+      printf ("  Tag_GNU_MIPS_ABI_FP: ");
+
+      switch (val)
+       {
+       case 0:
+         printf ("Hard or soft float\n");
+         break;
+       case 1:
+         printf ("Hard float (-mdouble-float)\n");
+         break;
+       case 2:
+         printf ("Hard float (-msingle-float)\n");
+         break;
+       case 3:
+         printf ("Soft float\n");
+         break;
+       default:
+         printf ("??? (%d)\n", val);
+         break;
+       }
+      return p;
+   }
+
+  if (tag & 1)
+    type = 1; /* String.  */
+  else
+    type = 2; /* uleb128.  */
+  printf ("  Tag_unknown_%d: ", tag);
+
+  if (type == 1)
+    {
+      printf ("\"%s\"\n", p);
+      p += strlen ((char *) p) + 1;
+    }
+  else
+    {
+      val = read_uleb128 (p, &len);
+      p += len;
+      printf ("%d (0x%x)\n", val, val);
+    }
+
+  return p;
+}
+
 static int
-process_arm_specific (FILE *file)
+process_attributes (FILE * file,
+                   const char * public_name,
+                   unsigned int proc_type,
+                   unsigned char * (* display_pub_attribute) (unsigned char *),
+                   unsigned char * (* display_proc_gnu_attribute) (unsigned char *, int))
 {
   Elf_Internal_Shdr *sect;
   unsigned char *contents;
@@ -8222,56 +8594,71 @@ process_arm_specific (FILE *file)
        i < elf_header.e_shnum;
        i++, sect++)
     {
-      if (sect->sh_type != SHT_ARM_ATTRIBUTES)
+      if (sect->sh_type != proc_type && sect->sh_type != SHT_GNU_ATTRIBUTES)
        continue;
 
       contents = get_data (NULL, file, sect->sh_offset, 1, sect->sh_size,
                           _("attributes"));
-
-      if (!contents)
+      if (contents == NULL)
        continue;
+
       p = contents;
       if (*p == 'A')
        {
          len = sect->sh_size - 1;
          p++;
+
          while (len > 0)
            {
              int namelen;
              bfd_boolean public_section;
+             bfd_boolean gnu_section;
 
              section_len = byte_get (p, 4);
              p += 4;
+
              if (section_len > len)
                {
                  printf (_("ERROR: Bad section length (%d > %d)\n"),
-                         (int)section_len, (int)len);
+                         (int) section_len, (int) len);
                  section_len = len;
                }
+
              len -= section_len;
              printf ("Attribute Section: %s\n", p);
-             if (strcmp ((char *)p, "aeabi") == 0)
+
+             if (public_name && streq ((char *) p, public_name))
                public_section = TRUE;
              else
                public_section = FALSE;
-             namelen = strlen ((char *)p) + 1;
+
+             if (streq ((char *) p, "gnu"))
+               gnu_section = TRUE;
+             else
+               gnu_section = FALSE;
+
+             namelen = strlen ((char *) p) + 1;
              p += namelen;
              section_len -= namelen + 4;
+
              while (section_len > 0)
                {
                  int tag = *(p++);
                  int val;
                  bfd_vma size;
+
                  size = byte_get (p, 4);
                  if (size > section_len)
                    {
                      printf (_("ERROR: Bad subsection length (%d > %d)\n"),
-                             (int)size, (int)section_len);
+                             (int) size, (int) section_len);
                      size = section_len;
                    }
+
                  section_len -= size;
                  end = p + size - 1;
                  p += 4;
+
                  switch (tag)
                    {
                    case 1:
@@ -8286,6 +8673,7 @@ process_arm_specific (FILE *file)
                      for (;;)
                        {
                          unsigned int i;
+
                          val = read_uleb128 (p, &i);
                          p += i;
                          if (val == 0)
@@ -8299,10 +8687,17 @@ process_arm_specific (FILE *file)
                      public_section = FALSE;
                      break;
                    }
+
                  if (public_section)
                    {
                      while (p < end)
-                       p = display_arm_attribute(p);
+                       p = display_pub_attribute (p);
+                   }
+                 else if (gnu_section)
+                   {
+                     while (p < end)
+                       p = display_gnu_attribute (p,
+                                                  display_proc_gnu_attribute);
                    }
                  else
                    {
@@ -8314,15 +8709,27 @@ process_arm_specific (FILE *file)
            }
        }
       else
-       {
-         printf (_("Unknown format '%c'\n"), *p);
-       }
+       printf (_("Unknown format '%c'\n"), *p);
 
-      free(contents);
+      free (contents);
     }
   return 1;
 }
 
+static int
+process_arm_specific (FILE *file)
+{
+  return process_attributes (file, "aeabi", SHT_ARM_ATTRIBUTES,
+                            display_arm_attribute, NULL);
+}
+
+static int
+process_power_specific (FILE *file)
+{
+  return process_attributes (file, NULL, SHT_GNU_ATTRIBUTES, NULL,
+                            display_power_gnu_attribute);
+}
+
 static int
 process_mips_specific (FILE *file)
 {
@@ -8333,6 +8740,9 @@ process_mips_specific (FILE *file)
   size_t options_offset = 0;
   size_t conflicts_offset = 0;
 
+  process_attributes (file, NULL, SHT_GNU_ATTRIBUTES, NULL,
+                     display_mips_gnu_attribute);
+
   /* We have a lot of special sections.  Thanks SGI!  */
   if (dynamic_section == NULL)
     /* No information available.  */
@@ -8427,9 +8837,7 @@ process_mips_specific (FILE *file)
                  int flags = liblist.l_flags;
                  size_t fcnt;
 
-                 for (fcnt = 0;
-                      fcnt < sizeof (l_flags_vals) / sizeof (l_flags_vals[0]);
-                      ++fcnt)
+                 for (fcnt = 0; fcnt < ARRAY_SIZE (l_flags_vals); ++fcnt)
                    if ((flags & l_flags_vals[fcnt].bit) != 0)
                      {
                        fputs (l_flags_vals[fcnt].name, stdout);
@@ -8466,7 +8874,7 @@ process_mips_specific (FILE *file)
          iopt = cmalloc ((sect->sh_size / sizeof (eopt)), sizeof (*iopt));
          if (iopt == NULL)
            {
-             error (_("Out of memory"));
+             error (_("Out of memory\n"));
              return 0;
            }
 
@@ -8651,14 +9059,14 @@ process_mips_specific (FILE *file)
 
       if (dynamic_symbols == NULL)
        {
-         error (_("conflict list found without a dynamic symbol table"));
+         error (_("conflict list found without a dynamic symbol table\n"));
          return 0;
        }
 
       iconf = cmalloc (conflictsno, sizeof (*iconf));
       if (iconf == NULL)
        {
-         error (_("Out of memory"));
+         error (_("Out of memory\n"));
          return 0;
        }
 
@@ -8850,6 +9258,27 @@ get_note_type (unsigned e_type)
   return buff;
 }
 
+static const char *
+get_gnu_elf_note_type (unsigned e_type)
+{
+  static char buff[64];
+
+  switch (e_type)
+    {
+    case NT_GNU_ABI_TAG:
+      return _("NT_GNU_ABI_TAG (ABI version tag)");
+    case NT_GNU_HWCAP:
+      return _("NT_GNU_HWCAP (DSO-supplied software HWCAP info)");
+    case NT_GNU_BUILD_ID:
+      return _("NT_GNU_BUILD_ID (unique build ID bitstring)");
+    default:
+      break;
+    }
+
+  snprintf (buff, sizeof (buff), _("Unknown note type: (0x%08x)"), e_type);
+  return buff;
+}
+
 static const char *
 get_netbsd_elfcore_note_type (unsigned e_type)
 {
@@ -8920,6 +9349,7 @@ get_netbsd_elfcore_note_type (unsigned e_type)
 static int
 process_note (Elf_Internal_Note *pnote)
 {
+  const char *name = pnote->namesz ? pnote->namedata : "(NONE)";
   const char *nt;
 
   if (pnote->namesz == 0)
@@ -8927,18 +9357,27 @@ process_note (Elf_Internal_Note *pnote)
        note type strings.  */
     nt = get_note_type (pnote->type);
 
+  else if (const_strneq (pnote->namedata, "GNU"))
+    /* GNU-specific object file notes.  */
+    nt = get_gnu_elf_note_type (pnote->type);
+
   else if (const_strneq (pnote->namedata, "NetBSD-CORE"))
     /* NetBSD-specific core file notes.  */
     nt = get_netbsd_elfcore_note_type (pnote->type);
 
+  else if (strneq (pnote->namedata, "SPU/", 4))
+    {
+      /* SPU-specific core file notes.  */
+      nt = pnote->namedata + 4;
+      name = "SPU";
+    }
+
   else
     /* Don't recognize this note name; just use the default set of
        note type strings.  */
       nt = get_note_type (pnote->type);
 
-  printf ("  %s\t\t0x%08lx\t%s\n",
-         pnote->namesz ? pnote->namedata : "(NONE)",
-         pnote->descsz, nt);
+  printf ("  %s\t\t0x%08lx\t%s\n", name, pnote->descsz, nt);
   return 1;
 }
 
@@ -9098,6 +9537,9 @@ process_arch_specific (FILE *file)
     case EM_MIPS_RS3_LE:
       return process_mips_specific (file);
       break;
+    case EM_PPC:
+      return process_power_specific (file);
+      break;
     default:
       break;
     }
@@ -9215,10 +9657,10 @@ process_object (char *file_name, FILE *file)
     }
 
   /* Initialise per file variables.  */
-  for (i = NUM_ELEM (version_info); i--;)
+  for (i = ARRAY_SIZE (version_info); i--;)
     version_info[i] = 0;
 
-  for (i = NUM_ELEM (dynamic_info); i--;)
+  for (i = ARRAY_SIZE (dynamic_info); i--;)
     dynamic_info[i] = 0;
 
   /* Process the file.  */
@@ -9230,16 +9672,17 @@ process_object (char *file_name, FILE *file)
      must make sure that the dump_sets array is zeroed out before each
      object file is processed.  */
   if (num_dump_sects > num_cmdline_dump_sects)
-    memset (dump_sects, 0, num_dump_sects);
+    memset (dump_sects, 0, num_dump_sects * sizeof (* dump_sects));
 
   if (num_cmdline_dump_sects > 0)
     {
       if (num_dump_sects == 0)
        /* A sneaky way of allocating the dump_sects array.  */
-       request_dump (num_cmdline_dump_sects, 0);
+       request_dump_bynumber (num_cmdline_dump_sects, 0);
 
       assert (num_dump_sects >= num_cmdline_dump_sects);
-      memcpy (dump_sects, cmdline_dump_sects, num_cmdline_dump_sects);
+      memcpy (dump_sects, cmdline_dump_sects,
+             num_cmdline_dump_sects * sizeof (* dump_sects));
     }
 
   if (! process_file_header ())
@@ -9375,7 +9818,8 @@ process_archive (char *file_name, FILE *file)
       return 1;
     }
 
-  if (const_strneq (arhdr.ar_name, "/               "))
+  if (const_strneq (arhdr.ar_name, "/               ")
+      || const_strneq (arhdr.ar_name, "/SYM64/         "))
     {
       /* This is the archive symbol table.  Skip it.
         FIXME: We should have an option to dump it.  */
@@ -9613,12 +10057,13 @@ main (int argc, char **argv)
   if (num_dump_sects > 0)
     {
       /* Make a copy of the dump_sects array.  */
-      cmdline_dump_sects = malloc (num_dump_sects);
+      cmdline_dump_sects = malloc (num_dump_sects * sizeof (* dump_sects));
       if (cmdline_dump_sects == NULL)
-       error (_("Out of memory allocating dump request table."));
+       error (_("Out of memory allocating dump request table.\n"));
       else
        {
-         memcpy (cmdline_dump_sects, dump_sects, num_dump_sects);
+         memcpy (cmdline_dump_sects, dump_sects,
+                 num_dump_sects * sizeof (* dump_sects));
          num_cmdline_dump_sects = num_dump_sects;
        }
     }
This page took 0.079906 seconds and 4 git commands to generate.