int
_bfd_vms_slurp_gsd (bfd * abfd, int objtype)
{
  int gsd_type, gsd_size;
  asection *section;
  unsigned char *vms_rec;
  flagword new_flags, old_flags;
  char *name;
  asymbol *symbol;
  vms_symbol_entry *entry;
  unsigned long base_addr;
  unsigned long align_addr;
  static unsigned int psect_idx = 0;

#if VMS_DEBUG
  vms_debug (2, "GSD/EGSD (%d/%x)\n", objtype, objtype);
#endif

  switch (objtype)
    {
    case EOBJ_S_C_EGSD:
      PRIV (vms_rec) += 8;	/* Skip type, size, l_temp.  */
      PRIV (rec_size) -= 8;
      break;
    case OBJ_S_C_GSD:
      PRIV (vms_rec) += 1;
      PRIV (rec_size) -= 1;
      break;
    default:
      return -1;
    }

  /* Calculate base address for each section.  */
  base_addr = 0L;

  abfd->symcount = 0;

  while (PRIV (rec_size) > 0)
    {
      vms_rec = PRIV (vms_rec);

      if (objtype == OBJ_S_C_GSD)
	gsd_type = vms_rec[0];
      else
	{
	  _bfd_vms_get_header_values (abfd, vms_rec, &gsd_type, &gsd_size);
	  gsd_type += EVAX_OFFSET;
	}

#if VMS_DEBUG
      vms_debug (3, "gsd_type %d\n", gsd_type);
#endif

      switch (gsd_type)
	{
	case GSD_S_C_PSC:
	  {
	    /* Program section definition.  */
	    asection *old_section = 0;

#if VMS_DEBUG
	    vms_debug (4, "GSD_S_C_PSC\n");
#endif
	    /* If this section isn't a bfd section.  */
	    if (PRIV (is_vax) && (psect_idx < (abfd->section_count - 1)))
	      {
		/* Check for temporary section from TIR record.  */
		if (psect_idx < PRIV (section_count))
		  old_section = PRIV (sections)[psect_idx];
		else
		  old_section = 0;
	      }

	    name = _bfd_vms_save_counted_string (vms_rec + 8);
	    section = bfd_make_section (abfd, name);
	    if (!section)
	      {
		(*_bfd_error_handler) (_("bfd_make_section (%s) failed"),
				       name);
		return -1;
	      }
	    old_flags = bfd_getl16 (vms_rec + 2);
	    section->size = bfd_getl32 (vms_rec + 4);  /* allocation */
	    new_flags = vms_secflag_by_name (abfd, vax_section_flags, name,
					     section->size > 0);
	    if (old_flags & EGPS_S_V_REL)
	      new_flags |= SEC_RELOC;
	    if (old_flags & GPS_S_M_OVR)
	      new_flags |= SEC_IS_COMMON;
	    if (!bfd_set_section_flags (abfd, section, new_flags))
	      {
		(*_bfd_error_handler)
		  (_("bfd_set_section_flags (%s, %x) failed"),
		   name, new_flags);
		return -1;
	      }
	    section->alignment_power = vms_rec[1];
	    align_addr = (1 << section->alignment_power);
	    if ((base_addr % align_addr) != 0)
	      base_addr += (align_addr - (base_addr % align_addr));
	    section->vma = (bfd_vma)base_addr;
	    base_addr += section->size;

	    /* Global section is common symbol.  */
	    if (old_flags & GPS_S_M_GBL)
	      {
		entry = _bfd_vms_enter_symbol (abfd, name);
		if (entry == NULL)
		  {
		    bfd_set_error (bfd_error_no_memory);
		    return -1;
		  }
		symbol = entry->symbol;

		symbol->value = 0;
		symbol->section = section;
		symbol->flags = (BSF_GLOBAL | BSF_SECTION_SYM | BSF_OLD_COMMON);
	      }

	    /* Copy saved contents if old_section set.  */
	    if (old_section != 0)
	      {
		section->contents = old_section->contents;
		if (section->size < old_section->size)
		  {
		    (*_bfd_error_handler)
		      (_("Size mismatch section %s=%lx, %s=%lx"),
		       old_section->name,
		       (unsigned long) old_section->size,
		       section->name,
		       (unsigned long) section->size);
		    return -1;
		  }
		else if (section->size > old_section->size)
		  {
		    section->contents = bfd_realloc (old_section->contents,
						     section->size);
		    if (section->contents == NULL)
		      {
			bfd_set_error (bfd_error_no_memory);
			return -1;
		      }
		  }
	      }
	    else
	      {
		section->contents = bfd_zmalloc (section->size);
		if (section->contents == NULL)
		  {
		    bfd_set_error (bfd_error_no_memory);
		    return -1;
		  }
	      }
#if VMS_DEBUG
	    vms_debug (4, "gsd psc %d (%s, flags %04x=%s) ",
		       section->index, name, old_flags, flag2str (gpsflagdesc, old_flags));
	    vms_debug (4, "%d bytes at 0x%08lx (mem %p)\n",
		       section->size, section->vma, section->contents);
#endif

	    gsd_size = vms_rec[8] + 9;

	    psect_idx++;
	  }
	  break;

	case GSD_S_C_EPM:
	case GSD_S_C_EPMW:
#if VMS_DEBUG
	  vms_debug (4, "gsd epm\n");
#endif
	  /* Fall through.  */
	case GSD_S_C_SYM:
	case GSD_S_C_SYMW:
	  {
	    int name_offset = 0, value_offset = 0;

	    /* Symbol specification (definition or reference).  */
#if VMS_DEBUG
	    vms_debug (4, "GSD_S_C_SYM(W)\n");
#endif
	    old_flags = bfd_getl16 (vms_rec + 2);
	    new_flags = BSF_NO_FLAGS;

	    if (old_flags & GSY_S_M_WEAK)
	      new_flags |= BSF_WEAK;

	    switch (gsd_type)
	      {
	      case GSD_S_C_EPM:
		name_offset = 11;
		value_offset = 5;
		new_flags |= BSF_FUNCTION;
		break;
	      case GSD_S_C_EPMW:
		name_offset = 12;
		value_offset = 6;
		new_flags |= BSF_FUNCTION;
		break;
	      case GSD_S_C_SYM:
		if (old_flags & GSY_S_M_DEF)	/* Symbol definition.  */
		  name_offset = 9;
		else
		  name_offset = 4;
		value_offset = 5;
		break;
	      case GSD_S_C_SYMW:
		if (old_flags & GSY_S_M_DEF)	/* Symbol definition.  */
		  name_offset = 10;
		else
		  name_offset = 5;
		value_offset = 6;
		break;
	      }

	    /* Save symbol in vms_symbol_table.  */
	    entry = _bfd_vms_enter_symbol
	      (abfd, _bfd_vms_save_counted_string (vms_rec + name_offset));
	    if (entry == NULL)
	      {
		bfd_set_error (bfd_error_no_memory);
		return -1;
	      }
	    symbol = entry->symbol;

	    if (old_flags & GSY_S_M_DEF)
	      {
		/* Symbol definition.  */
		int psect;

		symbol->value = bfd_getl32 (vms_rec + value_offset);
		if ((gsd_type == GSD_S_C_SYMW)
		    || (gsd_type == GSD_S_C_EPMW))
		  psect = bfd_getl16 (vms_rec + value_offset - 2);
		else
		  psect = vms_rec[value_offset-1];

		symbol->section = (asection *)(unsigned long)psect;
#if VMS_DEBUG
		vms_debug (4, "gsd sym def #%d (%s, %ld, %04x=%s)\n", abfd->symcount,
			  symbol->name, (long)symbol->section, old_flags, flag2str(gsyflagdesc, old_flags));
#endif
	      }
	    else
	      {
		/* Symbol reference.  */
#if VMS_DEBUG
		vms_debug (4, "gsd sym ref #%d (%s, %04x=%s)\n", abfd->symcount,
			   symbol->name, old_flags, flag2str (gsyflagdesc, old_flags));
#endif
		symbol->section = (asection *)(unsigned long)-1;
	      }

	    gsd_size = vms_rec[name_offset] + name_offset + 1;
	    symbol->flags = new_flags;
	  }

	  break;

	case GSD_S_C_PRO:
	case GSD_S_C_PROW:
#if VMS_DEBUG
	  vms_debug (4, "gsd pro\n");
#endif
	  break;
	case GSD_S_C_IDC:
#if VMS_DEBUG
	  vms_debug (4, "gsd idc\n");
#endif
	  break;
	case GSD_S_C_ENV:
#if VMS_DEBUG
	  vms_debug (4, "gsd env\n");
#endif
	  break;
	case GSD_S_C_LSY:
#if VMS_DEBUG
	  vms_debug (4, "gsd lsy\n");
#endif
	  break;
	case GSD_S_C_LEPM:
#if VMS_DEBUG
	  vms_debug (4, "gsd lepm\n");
#endif
	  break;
	case GSD_S_C_LPRO:
#if VMS_DEBUG
	  vms_debug (4, "gsd lpro\n");
#endif
	  break;
	case GSD_S_C_SPSC:
#if VMS_DEBUG
	  vms_debug (4, "gsd spsc\n");
#endif
	  break;
	case GSD_S_C_SYMV:
#if VMS_DEBUG
	  vms_debug (4, "gsd symv\n");
#endif
	  break;
	case GSD_S_C_EPMV:
#if VMS_DEBUG
	  vms_debug (4, "gsd epmv\n");
#endif
	  break;
	case GSD_S_C_PROV:
#if VMS_DEBUG
	  vms_debug (4, "gsd prov\n");
#endif
	  break;

	case EGSD_S_C_PSC + EVAX_OFFSET:
	  {
	    /* Program section definition.  */
	    name = _bfd_vms_save_counted_string (vms_rec + EGPS_S_B_NAMLNG);
	    section = bfd_make_section (abfd, name);
	    if (!section)
	      return -1;
	    old_flags = bfd_getl16 (vms_rec + EGPS_S_W_FLAGS);
	    section->size = bfd_getl32 (vms_rec + EGPS_S_L_ALLOC);
	    new_flags = vms_secflag_by_name (abfd, evax_section_flags, name,
					     section->size > 0);
	    if (old_flags & EGPS_S_V_REL)
	      new_flags |= SEC_RELOC;
	    if (!bfd_set_section_flags (abfd, section, new_flags))
	      return -1;
	    section->alignment_power = vms_rec[EGPS_S_B_ALIGN];
	    align_addr = (1 << section->alignment_power);
	    if ((base_addr % align_addr) != 0)
	      base_addr += (align_addr - (base_addr % align_addr));
	    section->vma = (bfd_vma)base_addr;
	    base_addr += section->size;
	    section->contents = bfd_zmalloc (section->size);
	    if (section->contents == NULL)
	      return -1;
	    section->filepos = (unsigned int)-1;
#if VMS_DEBUG
	    vms_debug (4, "EGSD P-section %d (%s, flags %04x=%s) ",
		       section->index, name, old_flags, flag2str(gpsflagdesc, old_flags));
	    vms_debug (4, "%d bytes at 0x%08lx (mem %p)\n",
		       section->size, section->vma, section->contents);
#endif
	  }
	  break;

	case EGSD_S_C_SYM + EVAX_OFFSET:
	  {
	    /* Global symbol specification (definition or reference).  */
	    symbol = bfd_make_empty_symbol (abfd);
	    if (symbol == 0)
	      return -1;

	    old_flags = bfd_getl16 (vms_rec + EGSY_S_W_FLAGS);
	    new_flags = BSF_NO_FLAGS;

	    if (old_flags & EGSY_S_V_WEAK)
	      new_flags |= BSF_WEAK;

	    if (old_flags & EGSY_S_V_DEF)
	      {
		/* Symbol definition.  */
		if (old_flags & EGSY_S_V_NORM)
		  new_flags |= BSF_FUNCTION;
		symbol->name =
		  _bfd_vms_save_counted_string (vms_rec + ESDF_S_B_NAMLNG);
		symbol->value = bfd_getl64 (vms_rec + ESDF_S_L_VALUE);
		symbol->section =
		  (asection *)(unsigned long) bfd_getl32 (vms_rec + ESDF_S_L_PSINDX);
#if VMS_DEBUG
		vms_debug (4, "EGSD sym def #%d (%s, %ld, %04x=%s)\n",
			   abfd->symcount, symbol->name, (long)symbol->section,
			   old_flags, flag2str (gsyflagdesc, old_flags));
#endif
	      }
	    else
	      {
		/* Symbol reference.  */
		symbol->name =
		  _bfd_vms_save_counted_string (vms_rec + ESRF_S_B_NAMLNG);
#if VMS_DEBUG
		vms_debug (4, "EGSD sym ref #%d (%s, %04x=%s)\n",
			   abfd->symcount, symbol->name, old_flags,
			   flag2str (gsyflagdesc, old_flags));
#endif
		symbol->section = (asection *)(unsigned long)-1;
	      }

	    symbol->flags = new_flags;

	    /* Register symbol in VMS symbol table.  */
	    entry = (vms_symbol_entry *) bfd_hash_lookup
	      (PRIV (vms_symbol_table), symbol->name, TRUE, FALSE);

	    if (entry == NULL)
	      {
		bfd_set_error (bfd_error_no_memory);
		return -1;
	      }

	    if (entry->symbol != NULL)
	      {
		/* FIXME ?, DEC C generates this.  */
#if VMS_DEBUG
		vms_debug (4, "EGSD_S_C_SYM: duplicate \"%s\"\n", symbol->name);
#endif
	      }
	    else
	      {
		entry->symbol = symbol;
		PRIV (gsd_sym_count)++;
		abfd->symcount++;
	      }
	  }
	  break;

	case EGSD_S_C_SYMG + EVAX_OFFSET:
	  {
	    /* Universal symbol specification (definition).  */
	    symbol = bfd_make_empty_symbol (abfd);
	    if (symbol == 0)
	      return -1;

	    old_flags = bfd_getl16 (vms_rec + EGST_S_W_FLAGS);
	    new_flags = BSF_NO_FLAGS;

	    if (old_flags & EGSY_S_V_WEAK)
	      new_flags |= BSF_WEAK;

	    if (old_flags & EGSY_S_V_DEF) /* symbol definition */
	      {
		if (old_flags & EGSY_S_V_NORM)
		  new_flags |= BSF_FUNCTION;

		symbol->name =
		  _bfd_vms_save_counted_string (vms_rec + EGST_S_B_NAMLNG);

		/* For BSF_FUNCTION symbols, the entry point is in LP_1
		   and the descriptor in LP_2.  For other symbols, the
		   unique value is in LP_2.  */
		symbol->value = bfd_getl64 (vms_rec + EGST_S_Q_LP_2);

		/* Adding this offset is necessary in order for GDB to
		   read the DWARF-2 debug info from shared libraries.  */
		if (abfd->flags & DYNAMIC
		    && strstr (symbol->name, "$DWARF2.DEBUG") != 0)
		  symbol->value += PRIV (symvva);
	      }
	    else /* symbol reference */
	      (*_bfd_error_handler) ("Invalid EGST reference");

	    symbol->flags = new_flags;

	    if (register_universal_symbol (abfd, symbol, old_flags) < 0)
	      return -1;

	    /* Make a second symbol for the entry point.  */
	    if (symbol->flags & BSF_FUNCTION)
	      {
		asymbol *en_sym;
		char *name = bfd_alloc (abfd, strlen (symbol->name) + 5);

		en_sym = bfd_make_empty_symbol (abfd);
		if (en_sym == 0)
		  return -1;

		strcpy (name, symbol->name);
		strcat (name, "..en");

		en_sym->name = name;
		en_sym->value = bfd_getl64 (vms_rec + EGST_S_Q_LP_1);

		if (register_universal_symbol (abfd, en_sym, old_flags) < 0)
		  return -1;
	      }
	  }
	  break;

	case EGSD_S_C_IDC + EVAX_OFFSET:
  	  break;

	default:
	  (*_bfd_error_handler) (_("Unknown GSD/EGSD subtype %d"), gsd_type);
	  bfd_set_error (bfd_error_bad_value);
	  return -1;
	}

      PRIV (rec_size) -= gsd_size;
      PRIV (vms_rec) += gsd_size;
    }

  if (abfd->symcount > 0)
    abfd->flags |= HAS_SYMS;

  return 0;
}
Esempio n. 2
0
/* Process GSD/EGSD record.
 * Return 0 on success, -1 on error.  */
int
_bfd_vms_slurp_gsd(bfd * abfd, int objtype)
{
#if defined(VMS_DEBUG) && VMS_DEBUG
  static struct flagdescstruct gpsflagdesc[] =
    {
      { "PIC", 0x0001 },
      { "LIB", 0x0002 },
      { "OVR", 0x0004 },
      { "REL", 0x0008 },
      { "GBL", 0x0010 },
      { "SHR", 0x0020 },
      { "EXE", 0x0040 },
      { "RD",  0x0080 },
      { "WRT", 0x0100 },
      { "VEC", 0x0200 },
      { "NOMOD", 0x0400 },
      { "COM", 0x0800 },
      { NULL, 0 }
    };

  static struct flagdescstruct gsyflagdesc[] =
    {
      { "WEAK", 0x0001 },
      { "DEF",  0x0002 },
      { "UNI",  0x0004 },
      { "REL",  0x0008 },
      { "COMM", 0x0010 },
      { "VECEP", 0x0020 },
      { "NORM", 0x0040 },
      { NULL, 0 }
    };
#endif /* VMS_DEBUG */

  int gsd_type, gsd_size;
  asection *section;
  unsigned char *vms_rec;
  flagword new_flags, old_flags;
  char *name;
  asymbol *symbol;
  vms_symbol_entry *entry;
  unsigned long base_addr;
  unsigned long align_addr;
  static unsigned int psect_idx = 0;

  gsd_size = 0;

#if defined(VMS_DEBUG) && VMS_DEBUG
  vms_debug(2, "GSD/EGSD (%d/%x)\n", objtype, objtype);
#endif /* VMS_DEBUG */

  switch (objtype)
    {
    case EOBJ_S_C_EGSD:
      PRIV(vms_rec) += 8;	/* Skip type, size, l_temp.  */
      PRIV(rec_size) -= 8;
      break;
    case OBJ_S_C_GSD:
      PRIV(vms_rec) += 1;
      PRIV(rec_size) -= 1;
      break;
    default:
      return -1;
    }

  /* Calculate base address for each section: */
  base_addr = 0L;

  abfd->symcount = 0;

  while (PRIV(rec_size) > 0)
    {
      vms_rec = PRIV(vms_rec);

      if (objtype == OBJ_S_C_GSD)
	gsd_type = *vms_rec;
      else
	{
	  _bfd_vms_get_header_values(abfd, vms_rec, &gsd_type, &gsd_size);
	  gsd_type += EVAX_OFFSET;
	}

#if defined(VMS_DEBUG) && VMS_DEBUG
      vms_debug (3, "gsd_type %d\n", gsd_type);
#endif

      switch (gsd_type)
	{
	case GSD_S_C_PSC:
	  {
	    /* Program section definition.  */
	    asection *old_section = 0;

#if defined(VMS_DEBUG) && VMS_DEBUG
	    vms_debug (4, "GSD_S_C_PSC\n");
#endif
	    /* If this section isn't a bfd section.  */
	    if (PRIV (is_vax) && (psect_idx < (abfd->section_count-1)))
	      {
		/* Check for temporary section from TIR record.  */
		if (psect_idx < PRIV (section_count))
		  old_section = PRIV (sections)[psect_idx];
		else
		  old_section = 0;
	      }

	    name = _bfd_vms_save_counted_string (vms_rec + 8);
	    section = bfd_make_section (abfd, name);
	    if (!section)
	      {
		(*_bfd_error_handler) (_("bfd_make_section (%s) failed"),
				       name);
		return -1;
	      }
	    old_flags = bfd_getl16 (vms_rec + 2);
	    section->size = bfd_getl32 (vms_rec + 4);  /* allocation */
	    new_flags = vms_secflag_by_name (abfd, vax_section_flags, name,
					     section->size > 0);
	    if (old_flags & EGPS_S_V_REL)
	      new_flags |= SEC_RELOC;
	    if (old_flags & GPS_S_M_OVR)
	      new_flags |= SEC_IS_COMMON;
	    if (!bfd_set_section_flags (abfd, section, new_flags))
	      {
		(*_bfd_error_handler)
		  (_("bfd_set_section_flags (%s, %x) failed"),
		   name, new_flags);
		return -1;
	      }
	    section->alignment_power = vms_rec[1];
	    align_addr = (1 << section->alignment_power);
	    if ((base_addr % align_addr) != 0)
	      base_addr += (align_addr - (base_addr % align_addr));
	    section->vma = (bfd_vma)base_addr;
	    base_addr += section->size;

	    /* Global section is common symbol.  */

	    if (old_flags & GPS_S_M_GBL)
	      {
		entry = _bfd_vms_enter_symbol (abfd, name);
		if (entry == NULL)
		  {
		    bfd_set_error (bfd_error_no_memory);
		    return -1;
		  }
		symbol = entry->symbol;

		symbol->value = 0;
		symbol->section = section;
		symbol->flags = (BSF_GLOBAL | BSF_SECTION_SYM | BSF_OLD_COMMON);
	      }

	    /* Copy saved contents if old_section set.  */
	    if (old_section != 0)
	      {
		section->contents = old_section->contents;
		if (section->size < old_section->size)
		  {
		    (*_bfd_error_handler)
		      (_("Size mismatch section %s=%lx, %s=%lx"),
		       old_section->name,
		       (unsigned long) old_section->size,
		       section->name,
		       (unsigned long) section->size);
		    return -1;
		  }
		else if (section->size > old_section->size)
		  {
		    section->contents = (unsigned char *)bfd_realloc(old_section->contents,
                                                                     section->size);
		    if (section->contents == NULL)
		      {
			bfd_set_error (bfd_error_no_memory);
			return -1;
		      }
		  }
	      }
	    else
	      {
		section->contents = (unsigned char *)bfd_zmalloc(section->size);
		if (section->contents == NULL)
		  {
		    bfd_set_error (bfd_error_no_memory);
		    return -1;
		  }
	      }
#if defined(VMS_DEBUG) && VMS_DEBUG
	    vms_debug (4, "gsd psc %d (%s, flags %04x=%s) ",
		       section->index, name, old_flags, flag2str (gpsflagdesc, old_flags));
	    vms_debug (4, "%d bytes at 0x%08lx (mem %p)\n",
		       section->size, section->vma, section->contents);
#endif /* VMS_DEBUG */

	    gsd_size = vms_rec[8] + 9;

	    psect_idx++;
	  }
	  break;

	case GSD_S_C_EPM:
	case GSD_S_C_EPMW:
#if defined(VMS_DEBUG) && VMS_DEBUG
	  vms_debug (4, "gsd epm\n");
#endif
	  /* Fall through.  */
	case GSD_S_C_SYM:
	case GSD_S_C_SYMW:
	  {
	    int name_offset = 0, value_offset = 0;

	    /* Symbol specification (definition or reference).  */
#if defined(VMS_DEBUG) && VMS_DEBUG
	    vms_debug(4, "GSD_S_C_SYM(W)\n");
#endif
	    old_flags = bfd_getl16 (vms_rec + 2);
	    new_flags = BSF_NO_FLAGS;

	    if (old_flags & GSY_S_M_WEAK)
	      new_flags |= BSF_WEAK;

	    switch (gsd_type) {
	      case GSD_S_C_EPM:
		name_offset = 11;
		value_offset = 5;
		new_flags |= BSF_FUNCTION;
		break;
	      case GSD_S_C_EPMW:
		name_offset = 12;
		value_offset = 6;
		new_flags |= BSF_FUNCTION;
		break;
	      case GSD_S_C_SYM:
		if (old_flags & GSY_S_M_DEF)	/* Symbol definition.  */
		  name_offset = 9;
		else
		  name_offset = 4;
		value_offset = 5;
		break;
	      case GSD_S_C_SYMW:
		if (old_flags & GSY_S_M_DEF)	/* Symbol definition.  */
		  name_offset = 10;
		else
		  name_offset = 5;
		value_offset = 6;
		break;
              default:
                break;
	    } /* end "switch (gsd_type)" */

	    /* Save symbol in vms_symbol_table: */
	    entry
              = _bfd_vms_enter_symbol(abfd,
                                      _bfd_vms_save_counted_string(vms_rec + name_offset));
	    if (entry == NULL)
	      {
		bfd_set_error (bfd_error_no_memory);
		return -1;
	      }
	    symbol = entry->symbol;

	    if (old_flags & GSY_S_M_DEF)
	      {
		/* Symbol definition.  */
		int psect;

		symbol->value = bfd_getl32 (vms_rec + value_offset);
		if ((gsd_type == GSD_S_C_SYMW)
		    || (gsd_type == GSD_S_C_EPMW))
		  psect = bfd_getl16 (vms_rec + value_offset - 2);
		else
		  psect = vms_rec[value_offset-1];

		symbol->section = (asection *) (size_t) psect;
#if defined(VMS_DEBUG) && VMS_DEBUG
		vms_debug (4, "gsd sym def #%d (%s, %d [%p], %04x=%s)\n", abfd->symcount,
			   symbol->name, (int)symbol->section, symbol->section, old_flags, flag2str (gsyflagdesc, old_flags));
#endif
	      }
	    else
	      {
		/* Symbol reference.  */
		symbol->section = bfd_make_section (abfd, BFD_UND_SECTION_NAME);
#if defined(VMS_DEBUG) && VMS_DEBUG
		vms_debug (4, "gsd sym ref #%d (%s, %s [%p], %04x=%s)\n",
			   abfd->symcount, symbol->name, symbol->section->name,
			   symbol->section, old_flags, flag2str (gsyflagdesc, old_flags));
#endif
	      }

	    gsd_size = vms_rec[name_offset] + name_offset + 1;
	    symbol->flags = new_flags;
	  }

	  break;

	case GSD_S_C_PRO:
	case GSD_S_C_PROW:
#if defined(VMS_DEBUG) && VMS_DEBUG
	  vms_debug (4, "gsd pro\n");
#endif
	  break;
	case GSD_S_C_IDC:
#if defined(VMS_DEBUG) && VMS_DEBUG
	  vms_debug (4, "gsd idc\n");
#endif
	  break;
	case GSD_S_C_ENV:
#if defined(VMS_DEBUG) && VMS_DEBUG
	  vms_debug (4, "gsd env\n");
#endif
	  break;
	case GSD_S_C_LSY:
#if defined(VMS_DEBUG) && VMS_DEBUG
	  vms_debug (4, "gsd lsy\n");
#endif
	  break;
	case GSD_S_C_LEPM:
#if defined(VMS_DEBUG) && VMS_DEBUG
	  vms_debug (4, "gsd lepm\n");
#endif
	  break;
	case GSD_S_C_LPRO:
#if defined(VMS_DEBUG) && VMS_DEBUG
	  vms_debug (4, "gsd lpro\n");
#endif
	  break;
	case GSD_S_C_SPSC:
#if defined(VMS_DEBUG) && VMS_DEBUG
	  vms_debug (4, "gsd spsc\n");
#endif
	  break;
	case GSD_S_C_SYMV:
#if defined(VMS_DEBUG) && VMS_DEBUG
	  vms_debug (4, "gsd symv\n");
#endif
	  break;
	case GSD_S_C_EPMV:
#if defined(VMS_DEBUG) && VMS_DEBUG
	  vms_debug (4, "gsd epmv\n");
#endif
	  break;
	case GSD_S_C_PROV:
#if defined(VMS_DEBUG) && VMS_DEBUG
	  vms_debug (4, "gsd prov\n");
#endif
	  break;

	case EGSD_S_C_PSC + EVAX_OFFSET:
	  {
	    /* Program section definition.  */
	    name = _bfd_vms_save_counted_string (vms_rec + 12);
	    section = bfd_make_section (abfd, name);
	    if (!section)
	      return -1;
	    old_flags = bfd_getl16 (vms_rec + 6);
	    section->size = bfd_getl32 (vms_rec + 8);	/* Allocation.  */
	    new_flags = vms_secflag_by_name (abfd, evax_section_flags, name,
					     section->size > 0);
	    if (old_flags & EGPS_S_V_REL)
	      new_flags |= SEC_RELOC;
	    if (!bfd_set_section_flags (abfd, section, new_flags))
	      return -1;
	    section->alignment_power = vms_rec[4];
	    align_addr = (1 << section->alignment_power);
	    if ((base_addr % align_addr) != 0)
	      base_addr += (align_addr - (base_addr % align_addr));
	    section->vma = (bfd_vma)base_addr;
	    base_addr += section->size;
	    section->contents = (unsigned char *)bfd_zmalloc(section->size);
	    if (section->contents == NULL)
	      return -1;
#if defined(VMS_DEBUG) && VMS_DEBUG
	    vms_debug (4, "egsd psc %d (%s, flags %04x=%s) ",
		       section->index, name, old_flags, flag2str (gpsflagdesc, old_flags));
	    vms_debug (4, "%d bytes at 0x%08lx (mem %p)\n",
		       section->size, section->vma, section->contents);
#endif
	  }
	  break;

	case EGSD_S_C_SYM + EVAX_OFFSET:
	  {
	    /* Symbol specification (definition or reference).  */
	    symbol = bfd_make_empty_symbol (abfd);
	    if (symbol == 0)
	      return -1;

	    old_flags = bfd_getl16 (vms_rec + 6);
	    new_flags = BSF_NO_FLAGS;

	    if (old_flags & EGSY_S_V_WEAK)
	      new_flags |= BSF_WEAK;

	    if (vms_rec[6] & EGSY_S_V_DEF)
	      {
		/* Symbol definition.  */
		symbol->name = _bfd_vms_save_counted_string (vms_rec + 32);
		if (old_flags & EGSY_S_V_NORM)
		  /* Proc def.  */
		  new_flags |= BSF_FUNCTION;

		symbol->value = bfd_getl64 (vms_rec + 8);
		symbol->section = (asection *) ((unsigned long) bfd_getl32 (vms_rec + 28));
#if defined(VMS_DEBUG) && VMS_DEBUG
		vms_debug (4, "egsd sym def #%d (%s, %d, %04x=%s)\n", abfd->symcount,
			   symbol->name, (int) symbol->section, old_flags,
			   flag2str (gsyflagdesc, old_flags));
#endif
	      }
	    else
	      {
		/* Symbol reference.  */
		symbol->name = _bfd_vms_save_counted_string (vms_rec + 8);
#if defined(VMS_DEBUG) && VMS_DEBUG
		vms_debug (4, "egsd sym ref #%d (%s, %04x=%s)\n", abfd->symcount,
			  symbol->name, old_flags, flag2str (gsyflagdesc, old_flags));
#endif
		symbol->section = bfd_make_section (abfd, BFD_UND_SECTION_NAME);
	      }

	    symbol->flags = new_flags;

	    /* Save symbol in vms_symbol_table: */
	    entry = (vms_symbol_entry *)bfd_hash_lookup(PRIV(vms_symbol_table),
                                                        symbol->name,
                                                        TRUE, FALSE);
	    if (entry == NULL)
	      {
		bfd_set_error(bfd_error_no_memory);
		return -1;
	      }

	    if (entry->symbol != NULL)
	      {
		/* FIXME ?, DEC C generates this.  */
#if defined(VMS_DEBUG) && VMS_DEBUG
		vms_debug(4, "EGSD_S_C_SYM: duplicate \"%s\"\n", symbol->name);
#endif /* VMS_DEBUG */
	      }
	    else
	      {
		entry->symbol = symbol;
		PRIV(gsd_sym_count)++;
		abfd->symcount++;
	      }
	  }
	  break;

	case EGSD_S_C_IDC + EVAX_OFFSET:
	  break;

	default:
	  (*_bfd_error_handler)(_("unknown gsd/egsd subtype %d"), gsd_type);
	  bfd_set_error(bfd_error_bad_value);
	  return -1;
	}

      PRIV(rec_size) -= gsd_size;
      PRIV(vms_rec) += gsd_size;
    }

  if (abfd->symcount > 0)
    abfd->flags |= HAS_SYMS;

  return 0;
}