* hppa-dis.c (print_insn_hppa): Output a space after 'X' completer.
[deliverable/binutils-gdb.git] / binutils / readelf.c
index c785a491eb4877f78c41d9a211353c3a71171c99..9a85549b50d05e8e03376cc073f1354fc48f3a9a 100644 (file)
@@ -67,6 +67,7 @@
 #include "elf/fr30.h"
 #include "elf/mcore.h"
 #include "elf/i960.h"
+#include "elf/pj.h"
 
 #include "bucomm.h"
 #include "getopt.h"
@@ -114,6 +115,7 @@ int                     do_debug_lines;
 int                     do_debug_pubnames;
 int                     do_debug_aranges;
 int                     do_arch;
+int                     do_notes;
 int                    is_32bit_elf;
 
 /* A dynamic array of flags indicating which sections require dumping.  */
@@ -177,7 +179,7 @@ static int                display_debug_abbrev        PARAMS ((Elf32_Internal_Sh
 static int                display_debug_aranges       PARAMS ((Elf32_Internal_Shdr *, unsigned char *, FILE *));
 static unsigned char *    process_abbrev_section      PARAMS ((unsigned char *, unsigned char *));
 static unsigned long      read_leb128                 PARAMS ((unsigned char *, int *, int));
-static int                process_extended_line_op    PARAMS ((unsigned char *, int));
+static int                process_extended_line_op    PARAMS ((unsigned char *, int, int));
 static void               reset_state_machine         PARAMS ((int));
 static char *             get_TAG_name                PARAMS ((unsigned long));
 static char *             get_AT_name                 PARAMS ((unsigned long));
@@ -193,6 +195,11 @@ static const char *       get_elf_class               PARAMS ((unsigned char));
 static const char *       get_data_encoding           PARAMS ((unsigned char));
 static const char *       get_osabi_name              PARAMS ((unsigned char));
 static int               guess_is_rela               PARAMS ((unsigned long));
+static char *            get_note_type                  PARAMS ((unsigned int));
+static int               process_note                   PARAMS ((Elf_External_Note *));
+static int               process_corefile_note_segment  PARAMS ((FILE *, unsigned long, unsigned long));
+static int               process_corefile_note_segments PARAMS ((FILE *));
+static int               process_corefile_contents      PARAMS ((FILE *));
 
 typedef int Elf32_Word;
 
@@ -734,6 +741,10 @@ dump_relocations (file, rel_offset, rel_size, symtab, nsyms, strtab, is_rela)
        case EM_PARISC:
          rtype = elf_hppa_reloc_type (type);
          break;
+
+       case EM_PJ:
+         rtype = elf_pj_reloc_type (type);
+         break;
        }
 
       if (rtype == NULL)
@@ -1026,7 +1037,7 @@ get_machine_name (e_machine)
     case EM_CYGNUS_MN10300:    return "mn10300";
     case EM_CYGNUS_MN10200:    return "mn10200";
     case EM_CYGNUS_FR30:       return "Fujitsu FR30";
-
+    case EM_PJ:                 return "picoJava";
     default:
       sprintf (buff, _("<unknown>: %x"), e_machine);
       return buff;
@@ -1140,6 +1151,14 @@ get_machine_flags (e_flags, e_machine)
          if ((e_flags & EF_SPARCV9_MM) == EF_SPARCV9_RMO)
            strcat (buf, ", rmo");
          break;
+
+       case EM_PJ:
+         if ((e_flags & EF_PICOJAVA_NEWCALLS) == EF_PICOJAVA_NEWCALLS)
+           strcat (buf, ", new calling convention");
+
+         if ((e_flags & EF_PICOJAVA_GNUCALLS) == EF_PICOJAVA_GNUCALLS)
+           strcat (buf, ", gnu calling convention");
+         break;
        }
     }
 
@@ -1335,6 +1354,7 @@ struct option options [] =
   {"symbols",          no_argument, 0, 's'},
   {"syms",             no_argument, 0, 's'},
   {"relocs",           no_argument, 0, 'r'},
+  {"notes",            no_argument, 0, 'n'},
   {"dynamic",          no_argument, 0, 'd'},
   {"arch-specific",    no_argument, 0, 'A'},
   {"version-info",     no_argument, 0, 'V'},
@@ -1363,6 +1383,7 @@ usage ()
   fprintf (stdout, _("                            Display the sections' header\n"));
   fprintf (stdout, _("  -e or --headers           Equivalent to: -h -l -S\n"));
   fprintf (stdout, _("  -s or --syms or --symbols Display the symbol table\n"));
+  fprintf (stdout, _("  -n or --notes             Display the core notes (if present)\n"));
   fprintf (stdout, _("  -r or --relocs            Display the relocations (if present)\n"));
   fprintf (stdout, _("  -d or --dynamic           Display the dynamic segment (if present)\n"));
   fprintf (stdout, _("  -V or --version-info      Display the version sections (if present)\n"));
@@ -1426,7 +1447,7 @@ parse_args (argc, argv)
     usage ();
 
   while ((c = getopt_long
-         (argc, argv, "ersahldSDAIw::x:i:vV", options, NULL)) != EOF)
+         (argc, argv, "ersahnldSDAIw::x:i:vV", options, NULL)) != EOF)
     {
       char *    cp;
       int      section;
@@ -1450,6 +1471,7 @@ parse_args (argc, argv)
          do_version ++;
          do_histogram ++;
          do_arch ++;
+         do_notes ++;
          break;
        case 'e':
          do_header ++;
@@ -1483,6 +1505,9 @@ parse_args (argc, argv)
        case 'I':
          do_histogram ++;
          break;
+       case 'n':
+         do_notes ++;
+         break;
        case 'x':
          do_dump ++;
          section = strtoul (optarg, & cp, 0);
@@ -1561,7 +1586,7 @@ parse_args (argc, argv)
 
   if (!do_dynamic && !do_syms && !do_reloc && !do_sections
       && !do_segments && !do_header && !do_dump && !do_version
-      && !do_histogram && !do_debugging && !do_arch)
+      && !do_histogram && !do_debugging && !do_arch && !do_notes)
     usage ();
   else if (argc < 3)
     {
@@ -4132,9 +4157,10 @@ reset_state_machine (is_stmt)
 /* Handled an extend line op.  Returns true if this is the end
    of sequence.  */
 static int
-process_extended_line_op (data, is_stmt)
+process_extended_line_op (data, is_stmt, pointer_size)
      unsigned char * data;
      int is_stmt;
+     int pointer_size;
 {
   unsigned char   op_code;
   int             bytes_read;
@@ -4164,8 +4190,7 @@ process_extended_line_op (data, is_stmt)
       break;
 
     case DW_LNE_set_address:
-      /* XXX - assumption here that address size is 4! */
-      adr = byte_get (data, 4);
+      adr = byte_get (data, pointer_size);
       printf (_("set Address to 0x%lx\n"), adr);
       state_machine_regs.address = adr;
       break;
@@ -4193,6 +4218,10 @@ process_extended_line_op (data, is_stmt)
   return len;
 }
 
+/* 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 int
 display_debug_lines (section, start, file)
@@ -4262,7 +4291,7 @@ display_debug_lines (section, start, file)
       printf (_("\n Opcodes:\n"));
       
       for (i = 1; i < info.li_opcode_base; i++)
-       printf (_("  Opcode %d has %d args\n"), i, standard_opcodes[i]);
+       printf (_("  Opcode %d has %d args\n"), i, standard_opcodes[i - 1]);
       
       /* Display the contents of the Directory table.  */
       data = standard_opcodes + info.li_opcode_base - 1;
@@ -4330,7 +4359,8 @@ display_debug_lines (section, start, file)
          switch (op_code)
            {
            case DW_LNS_extended_op:
-             data += process_extended_line_op (data, info.li_default_is_stmt);
+             data += process_extended_line_op (data, info.li_default_is_stmt,
+                                                debug_line_pointer_size);
              break;
              
            case DW_LNS_copy:
@@ -5754,6 +5784,7 @@ display_debug_aranges (section, start, file)
       unsigned char *          ranges;
       unsigned long            length;
       unsigned long            address;
+      int                     excess;
 
       external = (DWARF2_External_ARange *) start;
 
@@ -5773,19 +5804,25 @@ display_debug_aranges (section, start, file)
 
       ranges = start + sizeof (* external);
 
+      /* Must pad to an alignment boundary that is twice the pointer size.  */
+      excess = sizeof (*external) % (2 * arange.ar_pointer_size);
+      if (excess)
+       ranges += (2 * arange.ar_pointer_size) - excess;
+
       for (;;)
        {
          address = byte_get (ranges, arange.ar_pointer_size);
 
-         if (address == 0)
-           break;
-
          ranges += arange.ar_pointer_size;
 
          length  = byte_get (ranges, arange.ar_pointer_size);
 
          ranges += arange.ar_pointer_size;
 
+         /* A pair of zeros marks the end of the list.  */
+         if (address == 0 && length == 0)
+           break;
+         
          printf ("    %8.8lx %lu\n", address, length);
        }
 
@@ -5810,27 +5847,47 @@ display_debug_not_supported (section, start, file)
   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 (section, start, file)
+     Elf32_Internal_Shdr * section ATTRIBUTE_UNUSED;
+     unsigned char *       start;
+     FILE *                file ATTRIBUTE_UNUSED;
+{
+  DWARF2_External_CompUnit * external;
+
+  external = (DWARF2_External_CompUnit *) start;
+
+  debug_line_pointer_size = BYTE_GET (external->cu_pointer_size);
+  return 0;
+}
+
   /* A structure containing the name of a debug section and a pointer
-     to a function that can decode it.  */
+     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.  */
 struct
 {
   char * name;
-  int (* display) PARAMS((Elf32_Internal_Shdr *, unsigned char *, FILE *));
+  int (* display) PARAMS ((Elf32_Internal_Shdr *, unsigned char *, FILE *));
+  int (* prescan) PARAMS ((Elf32_Internal_Shdr *, unsigned char *, FILE *));
 }
 debug_displays[] =
 {
-  { ".debug_info",        display_debug_info },
-  { ".debug_abbrev",      display_debug_abbrev },
-  { ".debug_line",        display_debug_lines },
-  { ".debug_aranges",     display_debug_aranges },
-  { ".debug_pubnames",    display_debug_pubnames },
-  { ".debug_macinfo",     display_debug_not_supported },
-  { ".debug_frame",       display_debug_not_supported },
-  { ".debug_str",         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 }
+  { ".debug_info",        display_debug_info, prescan_debug_info },
+  { ".debug_abbrev",      display_debug_abbrev, NULL },
+  { ".debug_line",        display_debug_lines, NULL },
+  { ".debug_aranges",     display_debug_aranges, NULL },
+  { ".debug_pubnames",    display_debug_pubnames, NULL },
+  { ".debug_macinfo",     display_debug_not_supported, NULL },
+  { ".debug_frame",       display_debug_not_supported, NULL },
+  { ".debug_str",         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 }
 };
 
 static int
@@ -5878,15 +5935,48 @@ static int
 process_section_contents (file)
      FILE * file;
 {
-  Elf32_Internal_Shdr *    section;
-  unsigned int  i;
+  Elf32_Internal_Shdr * section;
+  unsigned int         i;
 
   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 < 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;
+               GET_DATA_ALLOC (section->sh_offset, length, start, unsigned char *,
+                               "debug section data");
+
+               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 ++)
     {
 #ifdef SUPPORT_DISASSEMBLY
@@ -6284,6 +6374,164 @@ process_mips_specific (file)
   return 1;
 }
 
+static char *
+get_note_type (e_type)
+     unsigned e_type;
+{
+  static char buff[64];
+  
+  switch (e_type)
+    {
+    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)");
+    case NT_TASKSTRUCT: return _("NT_TASKSTRUCT (task structure)");
+    case NT_PSTATUS:   return _("NT_PSTATUS (pstatus structure)");
+    case NT_FPREGS:    return _("NT_FPREGS (floating point registers)");
+    case NT_PSINFO:    return _("NT_PSINFO (psinfo structure)");
+    case NT_LWPSTATUS: return _("NT_LWPSTATUS (lwpstatus_t structure)");
+    case NT_LWPSINFO:  return _("NT_LWPSINFO (lwpsinfo_t structure)");
+    default:
+      sprintf (buff, _("Unknown note type: (0x%08x)"), e_type);
+      return buff;
+    }
+}
+
+static int
+process_note (pnote)
+  Elf_External_Note * pnote;
+{
+  Elf32_Internal_Note * internal;
+  char * pname;
+  
+  internal = (Elf32_Internal_Note *) pnote;
+  pname = malloc (internal->namesz + 1);
+  
+  if (pname == NULL)
+    {
+      error (_("Out of memory\n"));
+      return 0;
+    }
+
+  memcpy (pname, pnote->name, internal->namesz);
+  pname[internal->namesz] = '\0';
+
+  printf ("  %s\t\t0x%08lx\t%s\n", 
+         pname, internal->descsz, get_note_type (internal->type));
+          
+  free (pname);
+
+  return 1;
+}
+
+static int
+process_corefile_note_segment (file, offset, length)
+     FILE * file;
+     unsigned long offset;
+     unsigned long length;
+{
+  Elf_External_Note *  pnotes;
+  Elf_External_Note *  external;
+  Elf32_Internal_Note* internal;
+  unsigned int        notesz;
+  unsigned int         nlength;
+  unsigned char *      p;
+  int                  res = 1;
+  
+  if (length <= 0)
+    return 0;
+    
+  GET_DATA_ALLOC (offset, length, pnotes, Elf_External_Note *, "notes");
+
+  external = pnotes; 
+  p = (unsigned char *) pnotes;
+  nlength = length;
+  printf (_("\nNotes at offset 0x%08lx with length 0x%08lx:\n"), offset, length);
+  printf (_("  Owner\t\tData size\tDescription\n"));
+  
+  while (nlength > 0)
+    {
+      res &= process_note (external);
+      
+      internal = (Elf32_Internal_Note *) p;
+      notesz   = 3 * sizeof(unsigned long) + internal->namesz + internal->descsz;
+      nlength -= notesz;
+      p       += notesz;
+      external = (Elf_External_Note *) p;
+    }
+
+  free (pnotes);
+  
+  return res;
+}
+
+static int
+process_corefile_note_segments (file)
+     FILE * file;
+{
+  Elf_Internal_Phdr * program_headers;
+  Elf_Internal_Phdr * segment;
+  unsigned int       i;
+  int                 res = 1;
+  
+  program_headers = (Elf_Internal_Phdr *) malloc
+    (elf_header.e_phnum * sizeof (Elf_Internal_Phdr));
+
+  if (program_headers == NULL)
+    {
+      error (_("Out of memory\n"));
+      return 0;
+    }
+
+  if (is_32bit_elf)
+    i = get_32bit_program_headers (file, program_headers);
+  else
+    i = get_64bit_program_headers (file, program_headers);
+
+  if (i == 0)
+    {
+      free (program_headers);
+      return 0;
+    }
+  
+  for (i = 0, segment = program_headers;
+       i < elf_header.e_phnum;
+       i ++, segment ++)
+    {
+      if (segment->p_type == PT_NOTE)
+       res &= process_corefile_note_segment (file, 
+                                             (unsigned long)segment->p_offset,
+                                             (unsigned long)segment->p_filesz);
+    }
+    
+  free (program_headers);
+
+  return res;
+}
+
+static int
+process_corefile_contents (file)
+     FILE * file;
+{
+  /* If we have not been asked to display the notes then do nothing.  */
+  if (! do_notes)
+    return 1;
+  
+  /* If file is not a core file then exit.  */
+  if (elf_header.e_type != ET_CORE)
+    return 1;
+    
+  /* No program headers means no NOTE segment.  */
+  if (elf_header.e_phnum == 0)
+    {
+      printf (_("No note segments present in the core file.\n"));
+      return 1;
+   }
+
+  return process_corefile_note_segments (file);
+}
+
 static int
 process_arch_specific (file)
      FILE * file;
@@ -6441,7 +6689,9 @@ process_file (file_name)
   process_version_sections (file);
 
   process_section_contents (file);
-
+  
+  process_corefile_contents (file);
+  
   process_arch_specific (file);
 
   fclose (file);
This page took 0.029554 seconds and 4 git commands to generate.