* readelf.c (display_debug_frames): Don't crash for mismatched
[binutils-gdb.git] / binutils / readelf.c
index 520b736395baabcc1ba54fd056e3249c1a3c8293..3561eff0a6eb915372dc99bd3777c4cd51a57b5d 100644 (file)
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
    02111-1307, USA.  */
 \f
+/* The difference between readelf and objdump:
 
+  Both programs are capabale of displaying the contents of ELF format files,
+  so why does the binutils project have two file dumpers ?
+
+  The reason is that objdump sees an ELF file through a BFD filter of the
+  world; if BFD has a bug where, say, it disagrees about a machine constant
+  in e_flags, then the odds are good that it will remain internally
+  consistent.  The linker sees it the BFD way, objdump sees it the BFD way,
+  GAS sees it the BFD way.  There was need for a tool to go find out what
+  the file actually says.
+
+  This is why the readelf program does not link against the BFD library - it
+  exists as an independent program to help verify the correct working of BFD.
+
+  There is also the case that readelf can provide more information about an
+  ELF file than is provided by objdump.  In particular it can display DWARF
+  debugging information which (at the moment) objdump cannot.  */
+\f
 #include <assert.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -310,7 +328,7 @@ byte_get_little_endian (unsigned char *field, int size)
       /* This is a special case, generated by the BYTE_GET8 macro.
         It means that we are loading an 8 byte value from a field
         in an external structure into an 8 byte value in a field
-        in an internal strcuture.  */
+        in an internal structure.  */
       return  ((bfd_vma) (field[0]))
        |    (((bfd_vma) (field[1])) << 8)
        |    (((bfd_vma) (field[2])) << 16)
@@ -536,7 +554,7 @@ byte_get_big_endian (unsigned char *field, int size)
       /* This is a special case, generated by the BYTE_GET8 macro.
         It means that we are loading an 8 byte value from a field
         in an external structure into an 8 byte value in a field
-        in an internal strcuture.  */
+        in an internal structure.  */
       return ((bfd_vma) (field[7]))
        |   (((bfd_vma) (field[6])) << 8)
        |   (((bfd_vma) (field[5])) << 16)
@@ -600,7 +618,6 @@ guess_is_rela (unsigned long e_machine)
     case EM_DLX:
     case EM_OPENRISC:
     case EM_OR32:
-    case EM_M32R:
     case EM_CYGNUS_M32R:
     case EM_D10V:
     case EM_CYGNUS_D10V:
@@ -650,6 +667,7 @@ guess_is_rela (unsigned long e_machine)
     case EM_IQ2000:
     case EM_XTENSA:
     case EM_XTENSA_OLD:
+    case EM_M32R:
       return TRUE;
 
     case EM_MMA:
@@ -1916,6 +1934,7 @@ get_machine_flags (unsigned e_flags, unsigned e_machine)
            case E_MIPS_ARCH_32: strcat (buf, ", mips32"); break;
            case E_MIPS_ARCH_32R2: strcat (buf, ", mips32r2"); break;
            case E_MIPS_ARCH_64: strcat (buf, ", mips64"); break;
+           case E_MIPS_ARCH_64R2: strcat (buf, ", mips64r2"); break;
            default: strcat (buf, ", unknown ISA"); break;
            }
 
@@ -2252,7 +2271,7 @@ get_ia64_section_type_name (unsigned int sh_type)
   /* If the top 8 bits are 0x78 the next 8 are the os/abi ID. */
   if ((sh_type & 0xFF000000) == SHT_IA_64_LOPSREG)
     return get_osabi_name ((sh_type & 0x00FF0000) >> 16);
-      
+
   switch (sh_type)
     {
     case SHT_IA_64_EXT:                  return "IA_64_EXT";
@@ -3459,7 +3478,7 @@ process_section_headers (FILE *file)
 
       if (string_table == NULL)
        return 0;
-      
+
       string_table_length = section->sh_size;
     }
 
@@ -3687,7 +3706,7 @@ process_relocs (FILE *file)
       const char *name;
       int has_dynamic_reloc;
       unsigned int i;
-      
+
       has_dynamic_reloc = 0;
 
       for (i = 0; i < ARRAY_SIZE (dynamic_relocations); i++)
@@ -4345,7 +4364,7 @@ dynamic_segment_ia64_val (Elf_Internal_Dyn *entry)
 {
   switch (entry->d_tag)
     {
-    case DT_IA_64_PLT_RESERVE: 
+    case DT_IA_64_PLT_RESERVE:
       /* First 3 slots reserved.  */
       print_vma (entry->d_un.d_ptr, PREFIX_HEX);
       printf (" -- ");
@@ -6054,7 +6073,7 @@ dump_section (Elf_Internal_Shdr *section, FILE *file)
 
   bytes = section->sh_size;
 
-  if (bytes == 0)
+  if (bytes == 0 || section->sh_type == SHT_NOBITS)
     {
       printf (_("\nSection '%s' has no data to dump.\n"),
              SECTION_NAME (section));
@@ -6114,7 +6133,7 @@ dump_section (Elf_Internal_Shdr *section, FILE *file)
       for (j = 0; j < lbytes; j++)
        {
          k = data[j];
-         if (k >= ' ' && k < 0x80)
+         if (k >= ' ' && k < 0x7f)
            printf ("%c", k);
          else
            printf (".");
@@ -6252,15 +6271,137 @@ process_extended_line_op (unsigned char *data, int is_stmt, int pointer_size)
   return len;
 }
 
+/* Finds section NAME inside FILE and returns a
+   pointer to it, or NULL upon failure.  */
+
+static Elf_Internal_Shdr *
+find_section (const char * name)
+{
+  Elf_Internal_Shdr *sec;
+  unsigned int i;
+
+  for (i = elf_header.e_shnum, sec = section_headers + i - 1;
+       i; --i, --sec)
+    if (strcmp (SECTION_NAME (sec), name) == 0)
+      break;
+
+  if (i && sec && sec->sh_size != 0)
+    return sec;
+
+  return NULL;
+}
+
 /* Size of pointers in the .debug_line section.  This information is not
    really present in that section.  It's obtained before dumping the debug
    sections by doing some pre-scan of the .debug_info section.  */
-static int debug_line_pointer_size = 4;
+static unsigned int * debug_line_pointer_sizes = NULL;
+static unsigned int   num_debug_line_pointer_sizes = 0;
+
+/* Locate and scan the .debug_info section in the file and record the pointer
+   sizes for the compilation units in it.  Usually an executable will have
+   just one pointer size, but this is not guaranteed, and so we try not to
+   make any assumptions.  Returns zero upon failure, or the number of
+   compilation units upon success.  */
+
+static unsigned int
+get_debug_line_pointer_sizes (FILE * file)
+{
+  Elf_Internal_Shdr * section;
+  unsigned char *     start;
+  unsigned char *     end;
+  unsigned char *     begin;
+  unsigned long       length;
+  unsigned int        num_units;
+  unsigned int        unit;
+
+  section = find_section (".debug_info");
+  if (section == NULL)
+    return 0;
+
+  length = section->sh_size;
+  start = get_data (NULL, file, section->sh_offset, section->sh_size,
+                   _("extracting pointer sizes from .debug_info section"));
+  if (start == NULL)
+    return 0;
+
+  end = start + section->sh_size;
+  /* First scan the section to get the number of comp units.  */
+  for (begin = start, num_units = 0; begin < end; num_units++)
+    {
+      /* Read the first 4 bytes.  For a 32-bit DWARF section, this will
+        be the length.  For a 64-bit DWARF section, it'll be the escape
+        code 0xffffffff followed by an 8 byte length.  */
+      length = byte_get (begin, 4);
+
+      if (length == 0xffffffff)
+       {
+         length = byte_get (begin + 4, 8);
+         begin += length + 12;
+       }
+      else
+       begin += length + 4;
+    }
+
+  if (num_units == 0)
+    {
+      error (_("No comp units in .debug_info section ?"));
+      free (start);
+      return 0;
+    }
+
+  /* Then allocate an array to hold the pointer sizes.  */
+  debug_line_pointer_sizes = malloc (num_units * sizeof * debug_line_pointer_sizes);
+  if (debug_line_pointer_sizes == NULL)
+    {
+      error (_("Not enough memory for a pointer size array of %u entries"),
+            num_units);
+      free (start);
+      return 0;
+    }
+
+  /* Populate the array.  */
+  for (begin = start, unit = 0; begin < end; unit++)
+    {
+      length = byte_get (begin, 4);
+      if (length == 0xffffffff)
+       {
+         /* For 64-bit DWARF, the 1-byte address_size field is 22 bytes
+            from the start of the section.  This is computed as follows:
+
+            unit_length:         12 bytes
+            version:              2 bytes
+            debug_abbrev_offset:  8 bytes
+            -----------------------------
+            Total:               22 bytes  */
+
+         debug_line_pointer_sizes [unit] = byte_get (begin + 22, 1);
+         length = byte_get (begin + 4, 8);
+         begin += length + 12;
+       }
+      else
+       {
+         /* For 32-bit DWARF, the 1-byte address_size field is 10 bytes from
+            the start of the section:
+
+            unit_length:          4 bytes
+            version:              2 bytes
+            debug_abbrev_offset:  4 bytes
+            -----------------------------
+            Total:               10 bytes  */
+
+         debug_line_pointer_sizes [unit] = byte_get (begin + 10, 1);
+         begin += length + 4;
+       }
+    }
+
+  free (start);
+  num_debug_line_pointer_sizes = num_units;
+  return num_units;
+}
 
 static int
 display_debug_lines (Elf_Internal_Shdr *section,
-                    unsigned char * start,
-                    FILE *file ATTRIBUTE_UNUSED)
+                    unsigned char *start, FILE *file)
 {
   unsigned char *hdrptr;
   DWARF2_Internal_LineInfo info;
@@ -6271,12 +6412,18 @@ display_debug_lines (Elf_Internal_Shdr *section,
   int i;
   int offset_size;
   int initial_length_size;
+  unsigned int comp_unit = 0;
 
   printf (_("\nDump of debug contents of section %s:\n\n"),
          SECTION_NAME (section));
 
+  if (num_debug_line_pointer_sizes == 0)
+    get_debug_line_pointer_sizes (file);
+
   while (data < end)
     {
+      unsigned int pointer_size;
+
       hdrptr = data;
 
       /* Check the length of the block.  */
@@ -6330,6 +6477,19 @@ display_debug_lines (Elf_Internal_Shdr *section,
       info.li_line_base <<= 24;
       info.li_line_base >>= 24;
 
+      /* Get the pointer size from the comp unit associated
+        with this block of line number information.  */
+      if (comp_unit >= num_debug_line_pointer_sizes)
+       {
+         error (_("Not enough comp units for .debug_lines section\n"));
+         return 0;
+       }
+      else
+       {
+         pointer_size = debug_line_pointer_sizes [comp_unit];
+         comp_unit ++;
+       }
+
       printf (_("  Length:                      %ld\n"), info.li_length);
       printf (_("  DWARF Version:               %d\n"), info.li_version);
       printf (_("  Prologue Length:             %d\n"), info.li_prologue_length);
@@ -6338,6 +6498,7 @@ display_debug_lines (Elf_Internal_Shdr *section,
       printf (_("  Line Base:                   %d\n"), info.li_line_base);
       printf (_("  Line Range:                  %d\n"), info.li_line_range);
       printf (_("  Opcode Base:                 %d\n"), info.li_opcode_base);
+      printf (_("  (Pointer size:               %u)\n"), pointer_size);
 
       end_of_sequence = data + info.li_length + initial_length_size;
 
@@ -6430,7 +6591,7 @@ display_debug_lines (Elf_Internal_Shdr *section,
            {
            case DW_LNS_extended_op:
              data += process_extended_line_op (data, info.li_default_is_stmt,
-                                               debug_line_pointer_size);
+                                               pointer_size);
              break;
 
            case DW_LNS_copy:
@@ -6846,7 +7007,7 @@ get_FORM_name (unsigned long form)
     }
 }
 
-/* FIXME:  There are better and more effiecint ways to handle
+/* FIXME:  There are better and more efficient ways to handle
    these structures.  For now though, I just want something that
    is simple to implement.  */
 typedef struct abbrev_attr
@@ -7469,20 +7630,14 @@ static void
 load_debug_loc (FILE *file)
 {
   Elf_Internal_Shdr *sec;
-  unsigned int i;
 
   /* If it is already loaded, do nothing.  */
   if (debug_loc_contents != NULL)
     return;
 
   /* Locate the .debug_loc section.  */
-  for (i = 0, sec = section_headers;
-       i < elf_header.e_shnum;
-       i++, sec++)
-    if (strcmp (SECTION_NAME (sec), ".debug_loc") == 0)
-      break;
-
-  if (i == elf_header.e_shnum || sec->sh_size == 0)
+  sec = find_section (".debug_loc");
+  if (sec == NULL)
     return;
 
   debug_loc_size = sec->sh_size;
@@ -7505,13 +7660,13 @@ free_debug_loc (void)
 
 static int
 display_debug_loc (Elf_Internal_Shdr *section,
-                  unsigned char *start,
-                  FILE *file ATTRIBUTE_UNUSED)
+                  unsigned char *start, FILE *file)
 {
   unsigned char *section_end;
   unsigned long bytes;
   unsigned char *section_begin = start;
   bfd_vma addr;
+  unsigned int comp_unit = 0;
 
   addr = section->sh_addr;
   bytes = section->sh_size;
@@ -7523,6 +7678,9 @@ display_debug_loc (Elf_Internal_Shdr *section,
       return 0;
     }
 
+  if (num_debug_line_pointer_sizes == 0)
+    get_debug_line_pointer_sizes (file);
+
   printf (_("Contents of the .debug_loc section:\n\n"));
   printf (_("\n    Offset   Begin    End      Expression\n"));
 
@@ -7532,21 +7690,29 @@ display_debug_loc (Elf_Internal_Shdr *section,
       unsigned long end;
       unsigned short length;
       unsigned long offset;
+      unsigned int pointer_size;
 
       offset = start - section_begin;
 
+      /* Get the pointer size from the comp unit associated
+        with this block of location information.  */
+      if (comp_unit >= num_debug_line_pointer_sizes)
+       {
+         error (_("Not enough comp units for .debug_loc section\n"));
+         return 0;
+       }
+      else
+       {
+         pointer_size = debug_line_pointer_sizes [comp_unit];
+         comp_unit ++;
+       }
+
       while (1)
        {
-         /* Normally, the lists in the debug_loc section are related to a
-            given compilation unit, and thus, we would use the pointer size
-            of that compilation unit.  However, since we are displaying it
-            seperately here, we either have to store pointer sizes of all
-            compilation units, or assume they don't change.   We assume,
-            like the debug_line display, that it doesn't change.  */
-         begin = byte_get (start, debug_line_pointer_size);
-         start += debug_line_pointer_size;
-         end = byte_get (start, debug_line_pointer_size);
-         start += debug_line_pointer_size;
+         begin = byte_get (start, pointer_size);
+         start += pointer_size;
+         end = byte_get (start, pointer_size);
+         start += pointer_size;
 
          if (begin == 0 && end == 0)
            break;
@@ -7562,7 +7728,7 @@ display_debug_loc (Elf_Internal_Shdr *section,
          start += 2;
 
          printf ("    %8.8lx %8.8lx %8.8lx (", offset, begin, end);
-         decode_location_expression (start, debug_line_pointer_size, length);
+         decode_location_expression (start, pointer_size, length);
          printf (")\n");
 
          start += length;
@@ -7579,20 +7745,14 @@ static void
 load_debug_str (FILE *file)
 {
   Elf_Internal_Shdr *sec;
-  unsigned int i;
 
   /* If it is already loaded, do nothing.  */
   if (debug_str_contents != NULL)
     return;
 
   /* Locate the .debug_str section.  */
-  for (i = 0, sec = section_headers;
-       i < elf_header.e_shnum;
-       i++, sec++)
-    if (strcmp (SECTION_NAME (sec), ".debug_str") == 0)
-      break;
-
-  if (i == elf_header.e_shnum || sec->sh_size == 0)
+  sec = find_section (".debug_str");
+  if (sec == NULL)
     return;
 
   debug_str_size = sec->sh_size;
@@ -7842,7 +8002,7 @@ read_and_display_attr_value (unsigned long attribute,
       break;
     }
 
-  /* For some attributes we can display futher information.  */
+  /* For some attributes we can display further information.  */
 
   printf ("\t");
 
@@ -8054,7 +8214,6 @@ display_debug_info (Elf_Internal_Shdr *section,
       unsigned char *hdrptr;
       unsigned char *cu_abbrev_offset_ptr;
       unsigned char *tags;
-      unsigned int i;
       int level;
       unsigned long cu_offset;
       int offset_size;
@@ -8178,13 +8337,8 @@ display_debug_info (Elf_Internal_Shdr *section,
        unsigned char *begin;
 
        /* Locate the .debug_abbrev section and process it.  */
-       for (i = 0, sec = section_headers;
-            i < elf_header.e_shnum;
-            i++, sec++)
-         if (strcmp (SECTION_NAME (sec), ".debug_abbrev") == 0)
-           break;
-
-       if (i == elf_header.e_shnum || sec->sh_size == 0)
+       sec = find_section (".debug_abbrev");
+       if (sec == NULL)
          {
            warn (_("Unable to locate .debug_abbrev section!\n"));
            return 0;
@@ -8996,13 +9150,19 @@ display_debug_frames (Elf_Internal_Shdr *section,
              if (! do_debug_frames_interp)
                printf ("  DW_CFA_restore_state\n");
              rs = remembered_state;
-             remembered_state = rs->next;
-             frame_need_space (fc, rs->ncols-1);
-             memcpy (fc->col_type, rs->col_type, rs->ncols);
-             memcpy (fc->col_offset, rs->col_offset, rs->ncols * sizeof (int));
-             free (rs->col_type);
-             free (rs->col_offset);
-             free (rs);
+             if (rs)
+               {
+                 remembered_state = rs->next;
+                 frame_need_space (fc, rs->ncols-1);
+                 memcpy (fc->col_type, rs->col_type, rs->ncols);
+                 memcpy (fc->col_offset, rs->col_offset,
+                         rs->ncols * sizeof (int));
+                 free (rs->col_type);
+                 free (rs->col_offset);
+                 free (rs);
+               }
+             else if (do_debug_frames_interp)
+               printf ("Mismatched DW_CFA_restore_state\n");
              break;
 
            case DW_CFA_def_cfa:
@@ -9148,80 +9308,31 @@ display_debug_not_supported (Elf_Internal_Shdr *section,
   return 1;
 }
 
-/* Pre-scan the .debug_info section to record the size of address.
-   When dumping the .debug_line, we use that size information, assuming
-   that all compilation units have the same address size.  */
-static int
-prescan_debug_info (Elf_Internal_Shdr *section ATTRIBUTE_UNUSED,
-                   unsigned char *start,
-                   FILE *file ATTRIBUTE_UNUSED)
-{
-  unsigned long length;
-
-  /* Read the first 4 bytes.  For a 32-bit DWARF section, this will
-     be the length.  For a 64-bit DWARF section, it'll be the escape
-     code 0xffffffff followed by an 8 byte length.  For the purposes
-     of this prescan, we don't care about the actual length, but the
-     presence of the escape bytes does affect the location of the byte
-     which describes the address size.  */
-  length = byte_get (start, 4);
-
-  if (length == 0xffffffff)
-    {
-      /* For 64-bit DWARF, the 1-byte address_size field is 22 bytes
-         from the start of the section.  This is computed as follows:
-
-           unit_length:         12 bytes
-           version:              2 bytes
-           debug_abbrev_offset:  8 bytes
-           -----------------------------
-           Total:               22 bytes  */
-
-      debug_line_pointer_size = byte_get (start + 22, 1);
-    }
-  else
-    {
-      /* For 32-bit DWARF, the 1-byte address_size field is 10 bytes from
-         the start of the section:
-           unit_length:          4 bytes
-           version:              2 bytes
-           debug_abbrev_offset:  4 bytes
-           -----------------------------
-           Total:               10 bytes  */
-
-      debug_line_pointer_size = byte_get (start + 10, 1);
-    }
-  return 0;
-}
-
-  /* A structure containing the name of a debug section and a pointer
-     to a function that can decode it.  The third field is a prescan
-     function to be run over the section before displaying any of the
-     sections.  */
+/* A structure containing the name of a debug section
+   and a pointer to a function that can decode it.  */
 struct
 {
   const char *const name;
   int (*display) (Elf_Internal_Shdr *, unsigned char *, FILE *);
-  int (*prescan) (Elf_Internal_Shdr *, unsigned char *, FILE *);
 }
 debug_displays[] =
 {
-  { ".debug_abbrev",           display_debug_abbrev, NULL },
-  { ".debug_aranges",          display_debug_aranges, NULL },
-  { ".debug_frame",            display_debug_frames, NULL },
-  { ".debug_info",             display_debug_info, prescan_debug_info },
-  { ".debug_line",             display_debug_lines, NULL },
-  { ".debug_pubnames",         display_debug_pubnames, NULL },
-  { ".eh_frame",               display_debug_frames, NULL },
-  { ".debug_macinfo",          display_debug_macinfo, NULL },
-  { ".debug_str",              display_debug_str, NULL },
-  { ".debug_loc",              display_debug_loc, NULL },
-  { ".debug_pubtypes",         display_debug_not_supported, NULL },
-  { ".debug_ranges",           display_debug_not_supported, NULL },
-  { ".debug_static_func",      display_debug_not_supported, NULL },
-  { ".debug_static_vars",      display_debug_not_supported, NULL },
-  { ".debug_types",            display_debug_not_supported, NULL },
-  { ".debug_weaknames",                display_debug_not_supported, NULL }
+  { ".debug_abbrev",           display_debug_abbrev },
+  { ".debug_aranges",          display_debug_aranges },
+  { ".debug_frame",            display_debug_frames },
+  { ".debug_info",             display_debug_info },
+  { ".debug_line",             display_debug_lines },
+  { ".debug_pubnames",         display_debug_pubnames },
+  { ".eh_frame",               display_debug_frames },
+  { ".debug_macinfo",          display_debug_macinfo },
+  { ".debug_str",              display_debug_str },
+  { ".debug_loc",              display_debug_loc },
+  { ".debug_pubtypes",         display_debug_not_supported },
+  { ".debug_ranges",           display_debug_not_supported },
+  { ".debug_static_func",      display_debug_not_supported },
+  { ".debug_static_vars",      display_debug_not_supported },
+  { ".debug_types",            display_debug_not_supported },
+  { ".debug_weaknames",                display_debug_not_supported }
 };
 
 static int
@@ -9276,42 +9387,6 @@ process_section_contents (FILE *file)
   if (! do_dump)
     return 1;
 
-  /* Pre-scan the debug sections to find some debug information not
-     present in some of them.  For the .debug_line, we must find out the
-     size of address (specified in .debug_info and .debug_aranges).  */
-  for (i = 0, section = section_headers;
-       i < elf_header.e_shnum && i < num_dump_sects;
-       i++, section++)
-    {
-      char *name = SECTION_NAME (section);
-      int j;
-
-      if (section->sh_size == 0)
-       continue;
-
-      /* See if there is some pre-scan operation for this section.  */
-      for (j = NUM_ELEM (debug_displays); j--;)
-       if (strcmp (debug_displays[j].name, name) == 0)
-         {
-           if (debug_displays[j].prescan != NULL)
-             {
-               bfd_size_type length;
-               unsigned char *start;
-
-               length = section->sh_size;
-               start = get_data (NULL, file, section->sh_offset, length,
-                                 _("debug section data"));
-               if (!start)
-                 return 0;
-
-               debug_displays[j].prescan (section, start, file);
-               free (start);
-             }
-
-           break;
-         }
-    }
-
   for (i = 0, section = section_headers;
        i < elf_header.e_shnum && i < num_dump_sects;
        i++, section++)
@@ -9718,8 +9793,8 @@ process_mips_specific (FILE *file)
          free (econf64);
        }
 
-      printf (_("\nSection '.conflict' contains %ld entries:\n"),
-             (long) conflictsno);
+      printf (_("\nSection '.conflict' contains %lu entries:\n"),
+             (unsigned long) conflictsno);
       puts (_("  Num:    Index       Value  Name"));
 
       for (cnt = 0; cnt < conflictsno; ++cnt)
@@ -9823,6 +9898,7 @@ get_note_type (unsigned e_type)
 
   switch (e_type)
     {
+    case NT_AUXV:      return _("NT_AUXV (auxiliary vector)");
     case NT_PRSTATUS:  return _("NT_PRSTATUS (prstatus structure)");
     case NT_FPREGSET:  return _("NT_FPREGSET (floating point registers)");
     case NT_PRPSINFO:  return _("NT_PRPSINFO (prpsinfo structure)");
@@ -10134,7 +10210,7 @@ get_file_header (FILE *file)
       /* If we have been compiled with sizeof (bfd_vma) == 4, then
         we will not be able to cope with the 64bit data found in
         64 ELF files.  Detect this now and abort before we start
-        overwritting things.  */
+        overwriting things.  */
       if (sizeof (bfd_vma) < 8)
        {
          error (_("This instance of readelf has been built without support for a\n\
@@ -10456,14 +10532,24 @@ process_file (char *file_name)
 
   if (stat (file_name, &statbuf) < 0)
     {
-      error (_("Cannot stat input file %s.\n"), file_name);
+      if (errno == ENOENT)
+       error (_("'%s': No such file\n"), file_name);
+      else
+       error (_("Could not locate '%s'.  System error message: %s\n"),
+              file_name, strerror (errno));
+      return 1;
+    }
+
+  if (! S_ISREG (statbuf.st_mode))
+    {
+      error (_("'%s' is not an ordinary file\n"), file_name);
       return 1;
     }
 
   file = fopen (file_name, "rb");
   if (file == NULL)
     {
-      error (_("Input file %s not found.\n"), file_name);
+      error (_("Input file '%s' is not readable.\n"), file_name);
       return 1;
     }