[Patch]: Improve readelf for ia64/OpenVMS

Tristan Gingold gingold@adacore.com
Fri Jun 11 09:38:00 GMT 2010


On Jun 11, 2010, at 10:36 AM, Nick Clifton wrote:

> Hi Tristan,
> 
>> This patch makes readelf dumps most of them if the object file is an IA64/OpenVMS file.
> 
> A couple of minor niggles:

Thank you for the review.  I have added your changes.  Here is the new patch.
The ChangeLog entries are the same, except for the typo pointed out by Hartmut.

Tristan.

diff --git a/binutils/readelf.c b/binutils/readelf.c
index 2ea1bf7..757fefb 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -577,6 +577,17 @@ read_uleb128 (unsigned char *data, unsigned int *length_return)
   return read_leb128 (data, length_return, 0);
 }
 
+/* Return true if the current file is for IA-64 machine and OpenVMS ABI.
+   This OS has so many departures from the ELF standard that we test it at
+   many places.  */
+
+static inline int
+is_ia64_vms (void)
+{
+  return elf_header.e_machine == EM_IA_64
+    && elf_header.e_ident[EI_OSABI] == ELFOSABI_OPENVMS;
+}
+
 /* Guess the relocation size commonly used by the specific machines.  */
 
 static int
@@ -1372,9 +1383,7 @@ dump_relocations (FILE * file,
 			       && elf_header.e_ident[EI_OSABI] == ELFOSABI_HPUX
 			       && psym->st_shndx == SHN_IA_64_ANSI_COMMON)
 			sec_name = "ANSI_COM";
-		      else if (elf_header.e_machine == EM_IA_64
-			       && (elf_header.e_ident[EI_OSABI]
-				   == ELFOSABI_OPENVMS)
+		      else if (is_ia64_vms ()
 			       && psym->st_shndx == SHN_IA_64_VMS_SYMVEC)
 			sec_name = "VMS_SYMVEC";
 		      else
@@ -2553,6 +2562,27 @@ get_machine_flags (unsigned e_flags, unsigned e_machine)
 	    strcat (buf, ", constant gp");
 	  if ((e_flags & EF_IA_64_ABSOLUTE))
 	    strcat (buf, ", absolute");
+          if (elf_header.e_ident[EI_OSABI] == ELFOSABI_OPENVMS)
+            {
+              if ((e_flags & EF_IA_64_VMS_LINKAGES))
+                strcat (buf, ", vms_linkages");
+              switch ((e_flags & EF_IA_64_VMS_COMCOD))
+                {
+                case EF_IA_64_VMS_COMCOD_SUCCESS:
+                  break;
+                case EF_IA_64_VMS_COMCOD_WARNING:
+                  strcat (buf, ", warning");
+                  break;
+                case EF_IA_64_VMS_COMCOD_ERROR:
+                  strcat (buf, ", error");
+                  break;
+                case EF_IA_64_VMS_COMCOD_ABORT:
+                  strcat (buf, ", abort");
+                  break;
+                default:
+                  abort ();
+                }
+            }
 	  break;
 
 	case EM_VAX:
@@ -3789,7 +3819,10 @@ process_program_headers (FILE * file)
 	      sec = find_section (".dynamic");
 	      if (sec == NULL || sec->sh_size == 0)
 		{
-		  error (_("no .dynamic section in the dynamic segment\n"));
+                  /* A corresponding .dynamic section is expected, but on
+                     IA-64/OpenVMS it is OK for it to be missing.  */
+                  if (!is_ia64_vms ())
+                    error (_("no .dynamic section in the dynamic segment\n"));
 		  break;
 		}
 
@@ -5038,6 +5071,187 @@ process_section_groups (FILE * file)
   return 1;
 }
 
+/* Data used to display dynamic fixups.  */
+
+struct ia64_vms_dynfixup
+{
+  bfd_vma needed_ident;		/* Library ident number.  */
+  bfd_vma needed;		/* Index in the dstrtab of the library name.  */
+  bfd_vma fixup_needed;		/* Index of the library.  */
+  bfd_vma fixup_rela_cnt;	/* Number of fixups.  */
+  bfd_vma fixup_rela_off;	/* Fixups offset in the dynamic segment.  */
+};
+
+/* Data used to display dynamic relocations.  */
+
+struct ia64_vms_dynimgrela
+{
+  bfd_vma img_rela_cnt;		/* Number of relocations.  */
+  bfd_vma img_rela_off;		/* Reloc offset in the dynamic segment.  */
+};
+
+/* Display IA-64 OpenVMS dynamic fixups (used to dynamically link a shared
+   library).  */
+
+static void
+dump_ia64_vms_dynamic_fixups (FILE *file, struct ia64_vms_dynfixup *fixup,
+                              const char *strtab, unsigned int strtab_sz)
+{
+  Elf64_External_VMS_IMAGE_FIXUP *imfs;
+  long i;
+  const char *lib_name;
+
+  imfs = get_data (NULL, file, dynamic_addr + fixup->fixup_rela_off,
+		   1, fixup->fixup_rela_cnt * sizeof (*imfs),
+		   _("dynamic section image fixups"));
+  if (!imfs)
+    return;
+
+  if (fixup->needed < strtab_sz)
+    lib_name = strtab + fixup->needed;
+  else
+    {
+      warn ("corrupt library name index of 0x%lx found in dynamic entry",
+            fixup->needed);
+      lib_name = "???";
+    }
+  printf (_("\nImage fixups for needed library #%d: %s - ident: %lx\n"),
+	  (int) fixup->fixup_needed, lib_name, (long) fixup->needed_ident);
+  printf
+    (_("Seg Offset           Type                             SymVec DataType\n"));
+
+  for (i = 0; i < (long) fixup->fixup_rela_cnt; i++)
+    {
+      unsigned int type;
+      const char *rtype;
+
+      printf ("%3u ", (unsigned) BYTE_GET (imfs [i].fixup_seg));
+      printf_vma ((bfd_vma) BYTE_GET (imfs [i].fixup_offset));
+      type = BYTE_GET (imfs [i].type);
+      rtype = elf_ia64_reloc_type (type);
+      if (rtype == NULL)
+        printf (" 0x%08x                       ", type);
+      else
+        printf (" %-32s ", rtype);
+      printf ("%6u ", (unsigned) BYTE_GET (imfs [i].symvec_index));
+      printf ("0x%08x\n", (unsigned) BYTE_GET (imfs [i].data_type));
+    }
+
+  free (imfs);
+}
+
+/* Display IA-64 OpenVMS dynamic relocations (used to relocate an image).  */
+
+static void
+dump_ia64_vms_dynamic_relocs (FILE *file, struct ia64_vms_dynimgrela *imgrela)
+{
+  Elf64_External_VMS_IMAGE_RELA *imrs;
+  long i;
+
+  imrs = get_data (NULL, file, dynamic_addr + imgrela->img_rela_off,
+		   1, imgrela->img_rela_cnt * sizeof (*imrs),
+		   _("dynamic section image relas"));
+  if (!imrs)
+    return;
+
+  printf (_("\nImage relocs\n"));
+  printf
+    (_("Seg Offset   Type                            Addend            Seg Sym Off\n"));
+
+  for (i = 0; i < (long) imgrela->img_rela_cnt; i++)
+    {
+      unsigned int type;
+      const char *rtype;
+
+      printf ("%3u ", (unsigned) BYTE_GET (imrs [i].rela_seg));
+      printf ("%08" BFD_VMA_FMT "x ",
+              (bfd_vma) BYTE_GET (imrs [i].rela_offset));
+      type = BYTE_GET (imrs [i].type);
+      rtype = elf_ia64_reloc_type (type);
+      if (rtype == NULL)
+        printf ("0x%08x                      ", type);
+      else
+        printf ("%-31s ", rtype);
+      print_vma (BYTE_GET (imrs [i].addend), FULL_HEX);
+      printf ("%3u ", (unsigned) BYTE_GET (imrs [i].sym_seg));
+      printf ("%08" BFD_VMA_FMT "x\n",
+              (bfd_vma) BYTE_GET (imrs [i].sym_offset));
+    }
+
+  free (imrs);
+}
+
+/* Display IA-64 OpenVMS dynamic relocations and fixups.  */
+
+static int
+process_ia64_vms_dynamic_relocs (FILE *file)
+{
+  struct ia64_vms_dynfixup fixup;
+  struct ia64_vms_dynimgrela imgrela;
+  Elf_Internal_Dyn *entry;
+  int res = 0;
+  bfd_vma strtab_off = 0;
+  bfd_vma strtab_sz = 0;
+  char *strtab = NULL;
+
+  memset (&fixup, 0, sizeof (fixup));
+  memset (&imgrela, 0, sizeof (imgrela));
+
+  /* Note: the order of the entries is specified by the OpenVMS specs.  */
+  for (entry = dynamic_section;
+       entry < dynamic_section + dynamic_nent;
+       entry++)
+    {
+      switch (entry->d_tag)
+        {
+        case DT_IA_64_VMS_STRTAB_OFFSET:
+          strtab_off = entry->d_un.d_val;
+          break;
+        case DT_STRSZ:
+          strtab_sz = entry->d_un.d_val;
+          if (strtab == NULL)
+            strtab = get_data (NULL, file, dynamic_addr + strtab_off,
+                               1, strtab_sz, _("dynamic string section"));
+          break;
+
+        case DT_IA_64_VMS_NEEDED_IDENT:
+          fixup.needed_ident = entry->d_un.d_val;
+          break;
+        case DT_NEEDED:
+          fixup.needed = entry->d_un.d_val;
+          break;
+        case DT_IA_64_VMS_FIXUP_NEEDED:
+          fixup.fixup_needed = entry->d_un.d_val;
+          break;
+        case DT_IA_64_VMS_FIXUP_RELA_CNT:
+          fixup.fixup_rela_cnt = entry->d_un.d_val;
+          break;
+        case DT_IA_64_VMS_FIXUP_RELA_OFF:
+          fixup.fixup_rela_off = entry->d_un.d_val;
+          res++;
+          dump_ia64_vms_dynamic_fixups (file, &fixup, strtab, strtab_sz);
+          break;
+
+        case DT_IA_64_VMS_IMG_RELA_CNT:
+	  imgrela.img_rela_cnt = entry->d_un.d_val;
+          break;
+        case DT_IA_64_VMS_IMG_RELA_OFF:
+	  imgrela.img_rela_off = entry->d_un.d_val;
+          res++;
+          dump_ia64_vms_dynamic_relocs (file, &imgrela);
+          break;
+
+        default:
+          break;
+	}
+    }
+
+  if (strtab != NULL)
+    free (strtab);
+
+  return res;
+}
+
 static struct
 {
   const char * name;
@@ -5109,6 +5323,9 @@ process_relocs (FILE * file)
 	    }
 	}
 
+      if (is_ia64_vms ())
+        has_dynamic_reloc |= process_ia64_vms_dynamic_relocs (file);
+
       if (! has_dynamic_reloc)
 	printf (_("\nThere are no dynamic relocations in this file.\n"));
     }
@@ -6667,6 +6884,29 @@ dynamic_section_parisc_val (Elf_Internal_Dyn * entry)
   putchar ('\n');
 }
 
+#ifdef BFD64
+
+/* VMS vs Unix time offset and factor.  */
+
+#define VMS_EPOCH_OFFSET 35067168000000000LL
+#define VMS_GRANULARITY_FACTOR 10000000
+
+/* Display a VMS time in a human readable format.  */
+
+static void
+print_vms_time (bfd_int64_t vmstime)
+{
+  struct tm *tm;
+  time_t unxtime;
+
+  unxtime = (vmstime - VMS_EPOCH_OFFSET) / VMS_GRANULARITY_FACTOR;
+  tm = gmtime (&unxtime);
+  printf ("%04u-%02u-%02uT%02u:%02u:%02u",
+          tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+          tm->tm_hour, tm->tm_min, tm->tm_sec);
+}
+#endif /* BFD64 */
+
 static void
 dynamic_section_ia64_val (Elf_Internal_Dyn * entry)
 {
@@ -6679,6 +6919,46 @@ dynamic_section_ia64_val (Elf_Internal_Dyn * entry)
       print_vma (entry->d_un.d_ptr + (3 * 8), PREFIX_HEX);
       break;
 
+    case DT_IA_64_VMS_LINKTIME:
+#ifdef BFD64
+      print_vms_time (entry->d_un.d_val);
+#endif
+      break;
+
+    case DT_IA_64_VMS_LNKFLAGS:
+      print_vma (entry->d_un.d_ptr, PREFIX_HEX);
+      if (entry->d_un.d_val & VMS_LF_CALL_DEBUG)
+        printf (" CALL_DEBUG");
+      if (entry->d_un.d_val & VMS_LF_NOP0BUFS)
+        printf (" NOP0BUFS");
+      if (entry->d_un.d_val & VMS_LF_P0IMAGE)
+        printf (" P0IMAGE");
+      if (entry->d_un.d_val & VMS_LF_MKTHREADS)
+        printf (" MKTHREADS");
+      if (entry->d_un.d_val & VMS_LF_UPCALLS)
+        printf (" UPCALLS");
+      if (entry->d_un.d_val & VMS_LF_IMGSTA)
+        printf (" IMGSTA");
+      if (entry->d_un.d_val & VMS_LF_INITIALIZE)
+        printf (" INITIALIZE");
+      if (entry->d_un.d_val & VMS_LF_MAIN)
+        printf (" MAIN");
+      if (entry->d_un.d_val & VMS_LF_EXE_INIT)
+        printf (" EXE_INIT");
+      if (entry->d_un.d_val & VMS_LF_TBK_IN_IMG)
+        printf (" TBK_IN_IMG");
+      if (entry->d_un.d_val & VMS_LF_DBG_IN_IMG)
+        printf (" DBG_IN_IMG");
+      if (entry->d_un.d_val & VMS_LF_TBK_IN_DSF)
+        printf (" TBK_IN_DSF");
+      if (entry->d_un.d_val & VMS_LF_DBG_IN_DSF)
+        printf (" DBG_IN_DSF");
+      if (entry->d_un.d_val & VMS_LF_SIGNATURES)
+        printf (" SIGNATURES");
+      if (entry->d_un.d_val & VMS_LF_REL_SEG_OFF)
+        printf (" REL_SEG_OFF");
+      break;
+
     default:
       print_vma (entry->d_un.d_ptr, PREFIX_HEX);
       break;
@@ -7973,6 +8253,67 @@ get_mips_symbol_other (unsigned int other)
 }
 
 static const char *
+get_ia64_symbol_other (unsigned int other)
+{
+  if (is_ia64_vms ())
+    {
+      static char res[32];
+
+      res[0] = 0;
+
+      /* Function types is for images and .STB files only.  */
+      switch (elf_header.e_type)
+        {
+        case ET_DYN:
+        case ET_EXEC:
+          switch (VMS_ST_FUNC_TYPE (other))
+            {
+            case VMS_SFT_CODE_ADDR:
+              strcat (res, " CA");
+              break;
+            case VMS_SFT_SYMV_IDX:
+              strcat (res, " VEC");
+              break;
+            case VMS_SFT_FD:
+              strcat (res, " FD");
+              break;
+            case VMS_SFT_RESERVE:
+              strcat (res, " RSV");
+              break;
+            default:
+              abort ();
+            }
+          break;
+        default:
+          break;
+        }
+      switch (VMS_ST_LINKAGE (other))
+        {
+        case VMS_STL_IGNORE:
+          strcat (res, " IGN");
+          break;
+        case VMS_STL_RESERVE:
+          strcat (res, " RSV");
+          break;
+        case VMS_STL_STD:
+          strcat (res, " STD");
+          break;
+        case VMS_STL_LNK:
+          strcat (res, " LNK");
+          break;
+        default:
+          abort ();
+        }
+
+      if (res[0] != 0)
+        return res + 1;
+      else
+        return res;
+    }
+  return NULL;
+}
+
+static const char *
 get_symbol_other (unsigned int other)
 {
   const char * result = NULL;
@@ -7985,6 +8326,10 @@ get_symbol_other (unsigned int other)
     {
     case EM_MIPS:
       result = get_mips_symbol_other (other);
+      break;
+    case EM_IA_64:
+      result = get_ia64_symbol_other (other);
+      break;
     default:
       break;
     }
diff --git a/include/elf/ia64.h b/include/elf/ia64.h
index 625933c..fb3d99f 100644
--- a/include/elf/ia64.h
+++ b/include/elf/ia64.h
@@ -45,6 +45,14 @@
 /* Not used yet.  */
 #define EF_IA_64_ABSOLUTE	    (1 << 8) /* Load at absolute addresses.  */
 
+/* OpenVMS speficic.  */
+#define EF_IA_64_VMS_COMCOD	    0x03   /* Completion code.  */
+#define EF_IA_64_VMS_COMCOD_SUCCESS 0
+#define EF_IA_64_VMS_COMCOD_WARNING 1
+#define EF_IA_64_VMS_COMCOD_ERROR   2
+#define EF_IA_64_VMS_COMCOD_ABORT   3
+#define EF_IA_64_VMS_LINKAGES	    0x04   /* Contains VMS linkages info.  */
+
 #define ELF_STRING_ia64_archext		".IA_64.archext"
 #define ELF_STRING_ia64_pltoff		".IA_64.pltoff"
 #define ELF_STRING_ia64_unwind		".IA_64.unwind"
@@ -159,6 +167,23 @@
 #define DT_IA_64_VMS_PLTGOT_SEG      (DT_LOOS + 64)
 #define DT_IA_64_VMS_FPMODE          (DT_LOOS + 66)
 
+/* Values for DT_IA_64_LNKFLAGS.  */
+#define VMS_LF_CALL_DEBUG	0x0001	/* Activate and call the debugger.  */
+#define VMS_LF_NOP0BUFS		0x0002	/* RMS use of P0 for i/o disabled.  */
+#define VMS_LF_P0IMAGE		0x0004	/* Image in P0 space only.  */
+#define VMS_LF_MKTHREADS	0x0008	/* Multiple kernel threads enabled.  */
+#define VMS_LF_UPCALLS		0x0010	/* Upcalls enabled.  */
+#define VMS_LF_IMGSTA		0x0020	/* Use SYS$IMGSTA.  */
+#define VMS_LF_INITIALIZE	0x0040	/* Image uses tfradr2.  */
+#define VMS_LF_MAIN		0x0080	/* Image uses tfradr3.  */
+#define VMS_LF_EXE_INIT		0x0200	/* Image uses tfradr4.  */
+#define VMS_LF_TBK_IN_IMG	0x0400	/* Traceback records in image.  */
+#define VMS_LF_DBG_IN_IMG	0x0800	/* Debug records in image.  */
+#define VMS_LF_TBK_IN_DSF	0x1000	/* Traceback records in DSF.  */
+#define VMS_LF_DBG_IN_DSF	0x2000	/* Debug records in DSF.  */
+#define VMS_LF_SIGNATURES	0x4000	/* Signatures present.  */
+#define VMS_LF_REL_SEG_OFF	0x8000	/* Maintain relative pos of seg.  */
+
 /* This section only used by HP-UX, The HP linker gives weak symbols
    precedence over regular common symbols.  We want common to override
    weak.  Using this common instead of SHN_COMMON does that.  */
@@ -168,6 +193,45 @@
    vector (only possible for image files).  */
 #define SHN_IA_64_VMS_SYMVEC SHN_LOOS
 
+/* OpenVMS IA64-specific symbol attributes.  */
+#define VMS_STO_VISIBILITY 3	  /* Alias of the standard field.  */
+#define VMS_ST_VISIBILITY(o) ((o) & VMS_STO_VISIBILITY)
+#define VMS_STO_FUNC_TYPE  0x30	  /* Function type.  */
+#define VMS_ST_FUNC_TYPE(o)  (((o) & VMS_STO_FUNC_TYPE) >> 4)
+# define VMS_SFT_CODE_ADDR 0	  /* Symbol value is a code address.  */
+# define VMS_SFT_SYMV_IDX  1	  /* Symbol value is a symbol vector index.  */
+# define VMS_SFT_FD	   2	  /* Symbol value is a function descriptor.  */
+# define VMS_SFT_RESERVE   3	  /* Reserved.  */
+#define VMS_STO_LINKAGE    0xc0
+#define VMS_ST_LINKAGE(o)  (((o) & VMS_STO_LINKAGE) >> 6)
+# define VMS_STL_IGNORE	   0	  /* No associated linkage.  */
+# define VMS_STL_RESERVE   1
+# define VMS_STL_STD	   2	  /* Standard linkage with return value.  */
+# define VMS_STL_LNK	   3	  /* Explicit represented in .vms_linkages.  */
+
+/* OpenVMS specific fixup and relocation structures.  */
+
+typedef struct
+{
+  unsigned char fixup_offset[8];
+  unsigned char type[4];
+  unsigned char fixup_seg[4];
+  unsigned char addend[8];
+  unsigned char symvec_index[4];
+  unsigned char data_type[4];
+} Elf64_External_VMS_IMAGE_FIXUP;
+
+typedef struct
+{
+  unsigned char rela_offset[8];
+  unsigned char type[4];
+  unsigned char rela_seg[4];
+  unsigned char addend[8];
+  unsigned char sym_offset[8];
+  unsigned char sym_seg[4];
+  unsigned char fill_1[4];
+} Elf64_External_VMS_IMAGE_RELA;
+
 /* IA64-specific relocation types: */
 
 /* Relocs apply to specific instructions within a bundle.  The least
@@ -282,6 +346,31 @@ START_RELOC_NUMBERS (elf_ia64_reloc_type)
   RELOC_NUMBER (R_IA64_LTOFF_DTPREL22, 0xba) /* @ltoff(@dtprel(s+a)), imm22 */
 
   FAKE_RELOC (R_IA64_MAX_RELOC_CODE, 0xba)
+
+  /* OpenVMS specific relocs.  */
+  RELOC_NUMBER (R_IA64_VMS_DIR8, 0x70000000)		/* S + A */
+  RELOC_NUMBER (R_IA64_VMS_DIR16LSB, 0x70000001)	/* S + A */
+  RELOC_NUMBER (R_IA64_VMS_CALL_SIGNATURE, 0x70000002)
+  RELOC_NUMBER (R_IA64_VMS_EXECLET_FUNC, 0x70000003)
+  RELOC_NUMBER (R_IA64_VMS_EXECLET_DATA, 0x70000004)
+  RELOC_NUMBER (R_IA64_VMS_FIX8, 0x70000005)		/* S + A */
+  RELOC_NUMBER (R_IA64_VMS_FIX16, 0x70000006)		/* S + A */
+  RELOC_NUMBER (R_IA64_VMS_FIX32, 0x70000007)		/* S + A */
+  RELOC_NUMBER (R_IA64_VMS_FIX64, 0x70000008)		/* S + A */
+  RELOC_NUMBER (R_IA64_VMS_FIXFD, 0x70000009)
+  RELOC_NUMBER (R_IA64_VMS_ACC_LOAD, 0x7000000a)	/* ACC = S + A */
+  RELOC_NUMBER (R_IA64_VMS_ACC_ADD, 0x7000000b)		/* ACC += S + A */
+  RELOC_NUMBER (R_IA64_VMS_ACC_SUB, 0x7000000c)		/* ACC -= S + A */
+  RELOC_NUMBER (R_IA64_VMS_ACC_MUL, 0x7000000d)		/* ACC *= S + A */
+  RELOC_NUMBER (R_IA64_VMS_ACC_DIV, 0x7000000e)		/* ACC /= S + A */
+  RELOC_NUMBER (R_IA64_VMS_ACC_AND, 0x7000000f)		/* ACC &= S + A */
+  RELOC_NUMBER (R_IA64_VMS_ACC_IOR, 0x70000010)		/* ACC |= S + A */
+  RELOC_NUMBER (R_IA64_VMS_ACC_EOR, 0x70000011)		/* ACC ^= S + A */
+  RELOC_NUMBER (R_IA64_VMS_ACC_ASH, 0x70000012)		/* ACC >>= S + A */
+  RELOC_NUMBER (R_IA64_VMS_ACC_STO8, 0x70000014)	/* ACC */
+  RELOC_NUMBER (R_IA64_VMS_ACC_STO16LSH, 0x70000015)	/* ACC */
+  RELOC_NUMBER (R_IA64_VMS_ACC_STO32LSH, 0x70000016)	/* ACC */
+  RELOC_NUMBER (R_IA64_VMS_ACC_STO64LSH, 0x70000017)	/* ACC */
 END_RELOC_NUMBERS (R_IA64_max)
 
 #endif /* _ELF_IA64_H */



More information about the Binutils mailing list