aboutsummaryrefslogtreecommitdiff
path: root/bfd/vms-hdr.c
diff options
context:
space:
mode:
authorTristan Gingold <gingold@adacore.com>2009-02-23 09:28:43 +0000
committerTristan Gingold <gingold@adacore.com>2009-02-23 09:28:43 +0000
commit0c37646508ccd3222db567f20d0ed44a9c3ba1d2 (patch)
tree494165a5852e9256b4ffc7b97d8a2ae557f26c59 /bfd/vms-hdr.c
parent6f43c46f4b7ae3ae4506773de7d41c61bd2be4fe (diff)
downloadbinutils-0c37646508ccd3222db567f20d0ed44a9c3ba1d2.zip
binutils-0c37646508ccd3222db567f20d0ed44a9c3ba1d2.tar.gz
binutils-0c37646508ccd3222db567f20d0ed44a9c3ba1d2.tar.bz2
2009-02-23 Tristan Gingold <gingold@adacore.com>
* vms.h: Update copyright year, fix comments, reorder declarations. (_bfd_save_vms_section): Remove the prototype. (EGPS_S_V_NO_SHIFT): New constant. (bfd_vms_set_section_flags): New prototype. (EGPS_S_B_ALIGN, EGPS_S_W_FLAGS, EGPS_S_L_ALLOC, EGPS_S_B_NAMLNG): New constants. (EGSY_S_W_FLAGS): Ditto. (EGSY_S_V_QUAD_VAL): Ditto. (ESDF_S_L_VALUE, ESDF_S_L_PSINDX, ESDF_S_B_NAMLNG): Ditto. (EGST_S_W_FLAGS, EGST_S_Q_LP_1, EGST_S_Q_LP_2, EGST_S_L_PSINDX, EGST_S_B_NAMLNG): Ditto. (ESRF_S_B_NAMLNG): Ditto. (ETIR_S_C_HEADER_SIZE): Ditto. (EGPS_S_V_ALLOC_64BIT): Ditto. (DST_S_C_EPILOG): Ditto. (DST_S_C_SRC_SETLNUM_L, DST_S_C_SRC_SETLNUM_W) : Ditto. (DST_S_C_SRC_INCRLNUM_B): Ditto. (DST_S_B_PCLINE_UNSBYTE, DST_S_W_PCLINE_UNSWORD): Ditto. (DST_S_L_PCLINE_UNSLONG): Ditto. (DST_S_B_MODBEG_NAME, DST_S_L_RTNBEG_ADDRESS) : Ditto (DST_S_B_RTNBEG_NAME, DST_S_L_RTNEND_SIZE): Ditto (DST_S_C_SOURCE_HEADER_SIZE): Ditto. (DST_S_B_SRC_DF_LENGTH, DST_S_W_SRC_DF_FILEID): Ditto. (DST_S_B_SRC_DF_FILENAME, DST_S_B_SRC_UNSBYTE): Ditto. (DST_S_B_SRC_UNSBYTE): Ditto. (DST_S_W_SRC_UNSWORD, DST_S_L_SRC_UNSLONG): Ditto. Add prototypes. (vms_section, vms_reloc): Remove types. (hdr_struc): Replaced by ... (hdr_struct): ... new type. (EMH_S_W_HDRTYP, EMH_S_B_STRLVL, EMH_S_L_ARCH1): New constants. (EMH_S_L_ARCH2, EMH_S_L_RECSIZ, EMH_S_B_NAMLNG): Ditto. (EMH_DATE_LENGTH): Ditto. (eom_struc): Replaced by ... (eom_struct): ... new type. (EEOM_S_L_TOTAL_LPS, EEOM_S_W_COMCOD, EEOM_S_B_TFRFLG): New constants. (EEOM_S_L_PSINDX, EEOM_S_L_TFRADR): Ditto. (EIHD_S_K_MAJORID, EIHD_S_K_MINORID, EIHD_S_K_EXE): Ditto. (EIHD_S_L_SIZE, EIHD_S_L_ISDOFF, EIHD_S_L_SYMDBGOFF): Ditto. (EIHD_S_Q_SYMVVA, EIHD_S_L_IMGTYPE): Ditto. (EISD_S_L_EISDSIZE, EISD_S_L_SECSIZE, EISD_S_Q_VIR_ADDR): Ditto. (EISD_S_L_FLAGS, EISD_S_L_VBN, EISD_S_R_CONTROL): Ditto. (EISD_S_L_IDENT, EISD_S_T_GBLNAM): Ditto. (EISD_S_M_GBL, EISD_S_M_CRF, EISD_S_M_DZRO, EISD_S_M_WRT): Ditto. (EISD_S_M_INITALCODE, EISD_S_M_BASED, EISD_S_M_FIXUPVEC): Ditto. (EISD_S_M_RESIDENT, EISD_S_M_VECTOR, EISD_S_M_PROTECT): Ditto. (EISD_S_M_LASTCLU, EISD_S_M_EXE, EISD_S_M_NONSHRADR): Ditto. (EISD_S_M_QUAD_LENGTH, EISD_S_M_ALLOC_64BIT): Ditto. (EIHS_S_L_DSTVBN, EIHS_S_L_DSTSIZE, EIHS_S_L_GSTVBN): Ditto. (EIHS_S_L_GSTSIZE, EIHS_S_L_DMTVBN, EIHS_S_L_DMTBYTES): Ditto. (DBG_S_L_DMT_MODBEG, DBG_S_L_DST_SIZE): Ditto. (DBG_S_W_DMT_PSECT_COUNT, DBG_S_C_DMT_HEADER_SIZE): Ditto. (DBG_S_L_DMT_PSECT_START, DBG_S_L_DMT_PSECT_LENGTH) (DBG_S_C_DMT_PSECT_SIZE): Ditto. (enum file_type_enum): New type. (struct location_struct): Removed. (struct fileinfo, struct srecinfo, struct lineinfo): New types. (struct funcinfo, struct module): Ditto. (struct vms_private_data_struct): Update fields. (struct vms_section_data_struct): New type. * vms.c: Update copyright year, fix comments, Fix includes for DECC, add prototypes. (vms_initialize): Use bfd_alloc instead of bfd_zalloc and remove some initializers. Use flavour to set is_vax, location_stack is removed. (struct pair): Declare. (fill_section_ptr): Initialize variables at declaration. Add guard to set SECTION_SYM flag, handlde und section. (vms_fixup_sections): Use struct pair for fill_section_ptr argument. (_bfd_vms_slurp_object_records): New function, replaces previous vms_object_p. (vms_slurp_module): New function. (vms_slurp_image): Ditto. (vms_object_p): Complete rewrite. (vms_mkobject): Use is_vax field to slect architecture. (free_reloc_stream): New function. (vms_convert_to_var): Ditto. (vms_convert_to_var_1): Ditto. (vms_convert_to_var_unix_filename): Ditto. (vms_close_and_cleanup): Call free_reloc_stream, convert file to VAR format on VMS. (vms_new_section_hook): Set alignment to 0, allocate private data. (vms_get_section_contents): Load content. (vms_get_symbol_info): Handle undefined section. (vms_find_nearest_line): Handle. (alloc_reloc_stream): New function. (vms_slurp_reloc_table): Ditto. (vms_get_reloc_upper_bound): Make it real. (vms_canonicalize_reloc): Do the real work. (alpha_howto_table): Add ALPHA_R_NOP, ALPHA_R_BSR, ALPHA_R_LDA, ALPHA_R_BOH. (vms_bfd_reloc_type_lookup): Handle NOP, BSR, LDA and BOH. (vms_set_arch_mach): Check arch. (vms_set_section_contents): Copy the content after allocation. (vms_alpha_vec): Update object flags. * vms-tir.c: Update copyright year, fix comments, add prototypes for new functions. (dst_define_location): New function. (dst_restore_location): New function. (dst_retrieve_location): New function. (dst_check_allocation): New function. (image_dump): Call dst_check_allocation. (image_write_b): Ditto. (image_write_w): Ditto. (image_write_l): Ditto. (image_write_q): Ditto. (cmd_name): Handle STA_LW, STA_QW, STO_OFF, STO_IMM, STO_IMMR, STO_LW, STO_QW, OPR_ADD, CTL_SETRB, STC_LP_PSB, CTL_DFLOC, CTL_STLOC, CTL_STKDL. Call error handler instead of abort if name is not known. (etir_sta): Add quarter_relocs argument and set it. Fix cast. (etir_sto): Ditto. (etir_opr): Ditto, return FALSE in case of error. (etir_ctl): Add quarter_relocs argument and set it, fix cast. Fix CTL_DFLOC, CTL_STLOC, CTL_STKDL. (etir_stc): Add quarter_relocs argument and set it, fix cast. Fix STC_LP, STC_LP_PSB, STC_GBL and STC_CGA. Handle STC_LP_PSB, STC_BSR_GBL, STC_LDA_GBL, STC_BOH_GBL. Move STC_NOP_PS, STC_BSR_PS, STC_LDA_PS, STC_BOH_PS, STC_NBH_PS. Return FALSE in case of error. (tir_sta): Change sign of psect. (tir_ctl): Ditto. (tir_cmd): Fix cast. Makes tir_table static const. (etir_cmd): Add quarter_relocs argument, makes etir_table const, add argument to explain. (analyze_etir): Initialize maxptr, add quarter_relocs declaration, move some declarations into inner scopes. Handle quarter_relocs and STO_IMM. (_bfd_vms_slurp_tir): Use constant instead of hard-coded values. (_bfd_vms_slurp_relocs): New function. (_bfd_vms_decode_relocs): New function. (sto_imm): Rewritten. (start_first_etbt_record): New function. (start_another_etbt_record): Ditto. (etir_output_check): Ditto. (defer_reloc_p): Ditto. (_bfd_vms_write_tir): Remove nextoffset, convert a while-loop to a for-loop. Correctly deals with contents, deals with .vmsdebug, rewritte relocations handling. (_bfd_vms_write_tbt): Removed. (_bfd_vms_write_dbg): Ditto. * vms-misc.c: Update copyright year, Fix comments. (_bfd_vms_get_header_values): Use 'size' instead of 'length'. (maybe_adjust_record_pointer_for_object): New function. (_bfd_vms_get_first_record): New function, replaces ... (_bfd_vms_get_record): .. removed. (_bfd_vms_get_object_record): New function. (_bfd_vms_get_object_record): New function. (vms_get_remaining_object_record): New function, replaces ... (_bfd_vms_get_next_record): ... removed. (add_new_contents): Removed. (_bfd_save_vms_section): Removed. (_bfd_get_vms_section): Removed. (_bfd_vms_output_flush): Write in VAR format. (new_symbol): Don't make UND section. * vms-hdr.c: Update copyright year, update list of record handled. (_bfd_vms_slurp_hdr): rec_length renamed to rec_size. (_bfd_vms_write_hdr): Strip vms and unix patches, add comments, truncate module name at 31 characters, use constants instead of hard-coded value, write BFD version instead of a fixed string. (_bfd_vms_slurp_ihd): New function. (_bfd_vms_slurp_isd): Ditto. (_bfd_vms_slurp_ihs): Ditto. (new_module): Ditto. (parse_module): Ditto (build_module_list): Ditto. (module_find_nearest_line): Ditto. (_bfd_vms_find_nearest_dst_line): Ditto. (vms_slurp_debug): Ditto. (_bfd_vms_slurp_dbg): Ditto. (_bfd_vms_slurp_tbt): Ditto. (_bfd_vms_write_dbg): Ditto. (_bfd_vms_write_tbt): Ditto. * vms-gsd.c: Update copyright year, update list of records handled. (EVAX_LITERALS_NAME): New macro. (evax_section_flags): Add an entry for EVAX_LITERALS_NAME. (gpsflagdesc, gsyflagdesc): Moved out of _bfd_vms_slurp_gsd. (register_universal_symbol): New function and prototype. (_bfd_vms_slurp_gsd): Fix indentations and casts, improve debug messages, use constants instead of hard-coded value, fix missing endianness conversion, handle global symbol (SYMG). (bfd_vms_set_section_flags): New function. (_bfd_vms_write_gsd): Don't write .vmsdebug section, handle section literals, fix indentation, handle section bfd and vms flags, don't output LIB$INITIALIZE symbol, fix handling of weak symbols, fix evax vs vax procedure descriptor, handle absolute symbols. * reloc.c (BFD_RELOC_ALPHA_NOP, BFD_RELOC_ALPHA_BSR, BFD_RELOC_ALPHA_LDA, BFD_RELOC_ALPHA_BOH): New relocations. * makefile.vms (DEFS): Fix flags for VMS. * bfdio.c (real_fopen): Handle multiple VMS fopen attributes. * bfd-in2.h: Regenerated. * libbfd.h: Regenerated.
Diffstat (limited to 'bfd/vms-hdr.c')
-rw-r--r--bfd/vms-hdr.c1090
1 files changed, 1065 insertions, 25 deletions
diff --git a/bfd/vms-hdr.c b/bfd/vms-hdr.c
index 11e1af6..6ad84dd 100644
--- a/bfd/vms-hdr.c
+++ b/bfd/vms-hdr.c
@@ -1,14 +1,31 @@
/* vms-hdr.c -- BFD back-end for VMS/VAX (openVMS/VAX) and
EVAX (openVMS/Alpha) files.
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006,
- 2007 Free Software Foundation, Inc.
+ 2007, 2008, 2009 Free Software Foundation, Inc.
HDR record handling functions
EMH record handling functions
- and
+
EOM record handling functions
EEOM record handling functions
+ IHD record handling functions
+ EIHD record handling functions
+
+ ISD record handling functions
+ EISD record handling functions
+
+ IHS record handling functions
+ EIHS record handling functions
+
+ DBG record handling functions
+ EDBG record handling functions
+
+ TBT record handling functions
+ ETBT record handling functions
+
+ DST/DMT section handling functions
+
Written by Klaus K"ampf (kkaempf@rmi.de)
This program is free software; you can redistribute it and/or modify
@@ -39,6 +56,20 @@
#include <alloca.h>
#endif
+static struct module *new_module (bfd *);
+static void parse_module
+ (bfd *, struct module *, unsigned char *, unsigned int);
+static struct module *build_module_list (bfd *);
+static bfd_boolean module_find_nearest_line
+ (bfd *, struct module *, bfd_vma, const char **, const char **,
+ unsigned int *);
+static int vms_slurp_debug (bfd *);
+
+#define SET_MODULE_PARSED(m) \
+ do { if ((m)->name == NULL) (m)->name = ""; } while (0)
+#define IS_MODULE_PARSED(m) ((m)->name != NULL)
+
+
/* Read & process emh record
return 0 on success, -1 on error. */
@@ -85,15 +116,15 @@ _bfd_vms_slurp_hdr (bfd *abfd, int objtype)
break;
case MHD_S_C_LNM:
- PRIV (hdr_data).hdr_c_lnm = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_length - 2));
+ PRIV (hdr_data).hdr_c_lnm = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_size - 2));
break;
case MHD_S_C_SRC:
- PRIV (hdr_data).hdr_c_src = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_length - 2));
+ PRIV (hdr_data).hdr_c_src = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_size - 2));
break;
case MHD_S_C_TTL:
- PRIV (hdr_data).hdr_c_ttl = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_length - 2));
+ PRIV (hdr_data).hdr_c_ttl = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_size - 2));
break;
case EMH_S_C_MHD + EVAX_OFFSET:
@@ -110,15 +141,15 @@ _bfd_vms_slurp_hdr (bfd *abfd, int objtype)
break;
case EMH_S_C_LNM + EVAX_OFFSET:
- PRIV (hdr_data).hdr_c_lnm = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_length - 6));
+ PRIV (hdr_data).hdr_c_lnm = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_size - 6));
break;
case EMH_S_C_SRC + EVAX_OFFSET:
- PRIV (hdr_data).hdr_c_src = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_length - 6));
+ PRIV (hdr_data).hdr_c_src = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_size - 6));
break;
case EMH_S_C_TTL + EVAX_OFFSET:
- PRIV (hdr_data).hdr_c_ttl = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_length - 6));
+ PRIV (hdr_data).hdr_c_ttl = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_size - 6));
break;
case MHD_S_C_CPR:
@@ -189,6 +220,7 @@ _bfd_vms_write_hdr (bfd *abfd, int objtype)
unsigned int symnum;
int had_case = 0;
int had_file = 0;
+ char version [256];
#if VMS_DEBUG
vms_debug (2, "vms_write_hdr (%p)\n", abfd);
@@ -213,27 +245,34 @@ _bfd_vms_write_hdr (bfd *abfd, int objtype)
fptr = bfd_get_filename (abfd);
fname = strdup (fptr);
+
+ /* Strip VMS path. */
fout = strrchr (fname, ']');
- if (fout == 0)
+ if (fout == NULL)
fout = strchr (fname, ':');
- if (fout != 0)
+ if (fout != NULL)
fout++;
else
fout = fname;
+ /* Strip UNIX path. */
+ fptr = strrchr (fout, '/');
+ if (fptr != NULL)
+ fout = fptr + 1;
+
/* Strip .obj suffix. */
- fptr = strrchr (fname, '.');
- if ((fptr != 0)
- && (strcasecmp (fptr, ".OBJ") == 0))
+ fptr = strrchr (fout, '.');
+ if (fptr != 0 && strcasecmp (fptr, ".OBJ") == 0)
*fptr = 0;
+ /* Convert to upper case and truncate at 31 characters.
+ (VMS object file format restricts module name length to 31). */
fptr = fout;
while (*fptr != 0)
{
*fptr = TOUPPER (*fptr);
fptr++;
- if ((*fptr == ';')
- || ((fptr - fout) > 31))
+ if (*fptr == ';' || (fptr - fout) >= 31)
*fptr = 0;
}
_bfd_vms_output_counted (abfd, fout);
@@ -243,13 +282,14 @@ _bfd_vms_write_hdr (bfd *abfd, int objtype)
_bfd_vms_output_counted (abfd, "NONAME");
_bfd_vms_output_counted (abfd, BFD_VERSION_STRING);
- _bfd_vms_output_dump (abfd, get_vms_time_string (), 17);
- _bfd_vms_output_fill (abfd, 0, 17);
+ _bfd_vms_output_dump (abfd, get_vms_time_string (), EMH_DATE_LENGTH);
+ _bfd_vms_output_fill (abfd, 0, EMH_DATE_LENGTH);
_bfd_vms_output_flush (abfd);
/* LMN. */
_bfd_vms_output_begin (abfd, EOBJ_S_C_EMH, EMH_S_C_LNM);
- _bfd_vms_output_dump (abfd, (unsigned char *) STRING_COMMA_LEN ("GAS proGIS"));
+ snprintf (version, sizeof (version), "GAS BFD v%s", BFD_VERSION_STRING);
+ _bfd_vms_output_dump (abfd, (unsigned char *)version, strlen (version));
_bfd_vms_output_flush (abfd);
/* SRC. */
@@ -320,10 +360,10 @@ _bfd_vms_slurp_eom (bfd *abfd, int objtype)
}
else
{
- PRIV (eom_data).eom_l_total_lps = bfd_getl32 (vms_rec + 4);
- PRIV (eom_data).eom_b_comcod = *(vms_rec + 8);
-
- if (PRIV (eom_data).eom_b_comcod > 1)
+ PRIV (eom_data).eom_l_total_lps
+ = bfd_getl32 (vms_rec + EEOM_S_L_TOTAL_LPS);
+ PRIV (eom_data).eom_w_comcod = bfd_getl16 (vms_rec + EEOM_S_W_COMCOD);
+ if (PRIV (eom_data).eom_w_comcod > 1)
{
(*_bfd_error_handler) (_("Object module NOT error-free !\n"));
bfd_set_error (bfd_error_bad_value);
@@ -333,9 +373,11 @@ _bfd_vms_slurp_eom (bfd *abfd, int objtype)
if (PRIV (rec_size) > 10)
{
PRIV (eom_data).eom_has_transfer = TRUE;
- PRIV (eom_data).eom_b_tfrflg = *(vms_rec + 9);
- PRIV (eom_data).eom_l_psindx = bfd_getl32 (vms_rec + 12);
- PRIV (eom_data).eom_l_tfradr = bfd_getl32 (vms_rec + 16);
+ PRIV (eom_data).eom_b_tfrflg = vms_rec[EEOM_S_B_TFRFLG];
+ PRIV (eom_data).eom_l_psindx
+ = bfd_getl32 (vms_rec + EEOM_S_L_PSINDX);
+ PRIV (eom_data).eom_l_tfradr
+ = bfd_getl32 (vms_rec + EEOM_S_L_TFRADR);
abfd->start_address = PRIV (eom_data).eom_l_tfradr;
}
@@ -377,3 +419,1001 @@ _bfd_vms_write_eom (bfd *abfd, int objtype)
_bfd_vms_output_end (abfd);
return 0;
}
+
+/* Read & process IHD/EIHD record.
+ Return 0 on success, -1 on error */
+int
+_bfd_vms_slurp_ihd (bfd *abfd, unsigned int *isd_offset,
+ unsigned int *ihs_offset)
+{
+ unsigned int imgtype, size;
+ bfd_vma symvva;
+
+#if VMS_DEBUG
+ vms_debug (8, "_bfd_vms_slurp_ihd\n");
+#endif
+
+ size = bfd_getl32 (PRIV (vms_rec) + EIHD_S_L_SIZE);
+ imgtype = bfd_getl32 (PRIV (vms_rec) + EIHD_S_L_IMGTYPE);
+
+ if (imgtype == EIHD_S_K_EXE)
+ abfd->flags |= EXEC_P;
+
+ symvva = bfd_getl64 (PRIV (vms_rec) + EIHD_S_Q_SYMVVA);
+ if (symvva != 0)
+ {
+ PRIV (symvva) = symvva;
+ abfd->flags |= DYNAMIC;
+ }
+
+ *isd_offset = bfd_getl32 (PRIV (vms_rec) + EIHD_S_L_ISDOFF);
+ *ihs_offset = bfd_getl32 (PRIV (vms_rec) + EIHD_S_L_SYMDBGOFF);
+
+#if VMS_DEBUG
+ vms_debug (4, "EIHD record size %d imgtype %d symvva 0x%llx isd %d ihs %d\n",
+ size, imgtype, symvva, *isd_offset, *ihs_offset);
+#endif
+
+ return 0;
+}
+
+/* Read & process ISD/EISD record
+ return 0 on success, -1 on error */
+
+int
+_bfd_vms_slurp_isd (bfd *abfd, unsigned int offset)
+{
+ int section_count = 0;
+ unsigned char *p;
+ unsigned int rec_size;
+
+#if VMS_DEBUG
+ vms_debug (8, "_bfd_vms_slurp_isd\n");
+#endif
+
+ for (p = PRIV (vms_rec) + offset;
+ (rec_size = bfd_getl32 (p + EISD_S_L_EISDSIZE)) != 0;
+ p += rec_size)
+ {
+ unsigned long long vaddr = bfd_getl64 (p + EISD_S_Q_VIR_ADDR);
+ unsigned int size = bfd_getl32 (p + EISD_S_L_SECSIZE);
+ unsigned int flags = bfd_getl32 (p + EISD_S_L_FLAGS);
+ unsigned int vbn = bfd_getl32 (p + EISD_S_L_VBN);
+ char *name = NULL;
+ asection *section;
+ flagword bfd_flags;
+
+#if VMS_DEBUG
+ vms_debug (4, "EISD record at 0x%x size 0x%x addr 0x%x bfd_flags 0x%x block %d\n",
+ p - PRIV (vms_rec), size, vaddr, flags, vbn);
+#endif
+
+ /* VMS combines psects from .obj files into isects in the .exe. This
+ process doesn't preserve enough information to reliably determine
+ what's in each section without examining the data. This is
+ especially true of DWARF debug sections. */
+ bfd_flags = SEC_ALLOC;
+
+ if (flags & EISD_S_M_EXE)
+ bfd_flags |= SEC_CODE | SEC_HAS_CONTENTS | SEC_LOAD;
+
+ if (flags & EISD_S_M_NONSHRADR)
+ bfd_flags |= SEC_DATA | SEC_HAS_CONTENTS | SEC_LOAD;
+
+ if (!(flags & EISD_S_M_WRT))
+ bfd_flags |= SEC_READONLY;
+
+ if (flags & EISD_S_M_DZRO)
+ bfd_flags |= SEC_DATA;
+
+ if (flags & EISD_S_M_FIXUPVEC)
+ bfd_flags |= SEC_DATA | SEC_HAS_CONTENTS | SEC_LOAD;
+
+ if (flags & EISD_S_M_CRF)
+ bfd_flags |= SEC_HAS_CONTENTS | SEC_LOAD;
+
+ if (flags & EISD_S_M_GBL)
+ {
+ name = _bfd_vms_save_counted_string (p + EISD_S_T_GBLNAM);
+ bfd_flags |= SEC_COFF_SHARED_LIBRARY;
+ bfd_flags &= ~(SEC_ALLOC | SEC_LOAD);
+ }
+ else
+ {
+ name = (char*) bfd_alloc (abfd, 32);
+ sprintf (name, "$LOCAL_%03d$", section_count++);
+ }
+
+ section = bfd_make_section (abfd, name);
+
+ if (!section)
+ return -1;
+
+ section->filepos = vbn ? VMS_BLOCK_SIZE * (vbn - 1) : (unsigned int)-1;
+ section->size = size;
+ section->vma = vaddr;
+
+ if (!bfd_set_section_flags (abfd, section, bfd_flags))
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Read & process IHS/EIHS record
+ return 0 on success, -1 on error */
+int
+_bfd_vms_slurp_ihs (bfd *abfd, unsigned int offset)
+{
+ unsigned char *p = PRIV (vms_rec) + offset;
+ unsigned int gstvbn = bfd_getl32 (p + EIHS_S_L_GSTVBN);
+ unsigned int gstsize ATTRIBUTE_UNUSED = bfd_getl32 (p + EIHS_S_L_GSTSIZE);
+ unsigned int dstvbn = bfd_getl32 (p + EIHS_S_L_DSTVBN);
+ unsigned int dstsize = bfd_getl32 (p + EIHS_S_L_DSTSIZE);
+ unsigned int dmtvbn = bfd_getl32 (p + EIHS_S_L_DMTVBN);
+ unsigned int dmtbytes = bfd_getl32 (p + EIHS_S_L_DMTBYTES);
+ asection *section;
+
+#if VMS_DEBUG
+ vms_debug (8, "_bfd_vms_slurp_ihs\n");
+ vms_debug (4, "EIHS record gstvbn %d gstsize %d dstvbn %d dstsize %d dmtvbn %d dmtbytes %d\n",
+ gstvbn, gstsize, dstvbn, dstsize, dmtvbn, dmtbytes);
+#endif
+
+ if (dstvbn)
+ {
+ flagword bfd_flags = SEC_HAS_CONTENTS | SEC_DEBUGGING;
+
+ section = bfd_make_section (abfd, "$DST$");
+ if (!section)
+ return -1;
+
+ section->size = dstsize;
+ section->filepos = VMS_BLOCK_SIZE * (dstvbn - 1);
+
+ if (!bfd_set_section_flags (abfd, section, bfd_flags))
+ return -1;
+
+ PRIV (dst_section) = section;
+ abfd->flags |= (HAS_DEBUG | HAS_LINENO);
+ }
+
+ if (dmtvbn)
+ {
+ flagword bfd_flags = SEC_HAS_CONTENTS | SEC_DEBUGGING;
+
+ section = bfd_make_section (abfd, "$DMT$");
+ if (!section)
+ return -1;
+
+ section->size = dmtbytes;
+ section->filepos = VMS_BLOCK_SIZE * (dmtvbn - 1);
+
+ if (!bfd_set_section_flags (abfd, section, bfd_flags))
+ return -1;
+ }
+
+ if (gstvbn)
+ {
+ flagword bfd_flags = SEC_HAS_CONTENTS;
+
+ section = bfd_make_section (abfd, "$GST$");
+ if (!section)
+ return -1;
+
+ if (bfd_seek (abfd, VMS_BLOCK_SIZE * (gstvbn - 1), SEEK_SET))
+ {
+ bfd_set_error (bfd_error_file_truncated);
+ return -1;
+ }
+
+ if (_bfd_vms_slurp_object_records (abfd) != 0)
+ return -1;
+
+ section->filepos = VMS_BLOCK_SIZE * (gstvbn - 1);
+ section->size = bfd_tell (abfd) - section->filepos;
+
+ if (!bfd_set_section_flags (abfd, section, bfd_flags))
+ return -1;
+
+ abfd->flags |= HAS_SYMS;
+ }
+
+ return 0;
+}
+
+/* Build a new module for the specified BFD. */
+
+static struct module *
+new_module (bfd *abfd)
+{
+ struct module *module
+ = (struct module *) bfd_zalloc (abfd, sizeof (struct module));
+ module->file_table_count = 16; /* Arbitrary. */
+ module->file_table
+ = bfd_malloc (module->file_table_count * sizeof (struct fileinfo));
+ return module;
+}
+
+/* Parse debug info for a module and internalize it. */
+
+static void
+parse_module (bfd *abfd, struct module *module, unsigned char *ptr,
+ unsigned int length)
+{
+ unsigned char *maxptr = ptr + length, *src_ptr, *pcl_ptr;
+ unsigned int prev_linum = 0, curr_linenum = 0;
+ bfd_vma prev_pc = 0, curr_pc = 0;
+ struct srecinfo *curr_srec, *srec;
+ struct lineinfo *curr_line, *line;
+ struct funcinfo *funcinfo;
+
+ /* Initialize tables with zero element. */
+ curr_srec = (struct srecinfo *) bfd_zalloc (abfd, sizeof (struct srecinfo));
+ module->srec_table = curr_srec;
+
+ curr_line = (struct lineinfo *) bfd_zalloc (abfd, sizeof (struct lineinfo));
+ module->line_table = curr_line;
+
+ while (ptr < maxptr)
+ {
+ /* The first byte is not counted in the recorded length. */
+ int rec_length = bfd_getl16 (ptr) + 1;
+ int rec_type = bfd_getl16 (ptr + 2);
+
+#if VMS_DEBUG
+ _bfd_vms_debug (2, "DST record: length %d, type %d\n",
+ rec_length, rec_type);
+#endif
+
+ switch (rec_type)
+ {
+ case DST_S_C_MODBEG:
+ module->name
+ = _bfd_vms_save_counted_string (ptr + DST_S_B_MODBEG_NAME);
+
+ curr_pc = 0;
+ prev_pc = 0;
+ curr_linenum = 0;
+ prev_linum = 0;
+
+#if VMS_DEBUG
+ _bfd_vms_debug (3, "module: %s\n", module->name);
+#endif
+ break;
+
+ case DST_S_C_MODEND:
+#if VMS_DEBUG
+ _bfd_vms_debug (3, "end module\n");
+#endif
+ break;
+
+ case DST_S_C_RTNBEG:
+ funcinfo = (struct funcinfo *)
+ bfd_zalloc (abfd, sizeof (struct funcinfo));
+ funcinfo->name
+ = _bfd_vms_save_counted_string (ptr + DST_S_B_RTNBEG_NAME);
+ funcinfo->low = bfd_getl32 (ptr + DST_S_L_RTNBEG_ADDRESS);
+ funcinfo->next = module->func_table;
+ module->func_table = funcinfo;
+
+#if VMS_DEBUG
+ _bfd_vms_debug (3, "routine: %s at 0x%x\n",
+ funcinfo->name, funcinfo->low);
+#endif
+ break;
+
+ case DST_S_C_RTNEND:
+ module->func_table->high = module->func_table->low
+ + bfd_getl32 (ptr + DST_S_L_RTNEND_SIZE) - 1;
+
+ if (module->func_table->high > module->high)
+ module->high = module->func_table->high;
+
+#if VMS_DEBUG
+ _bfd_vms_debug (3, "end routine\n");
+#endif
+ break;
+
+ case DST_S_C_PROLOG:
+#if VMS_DEBUG
+ _bfd_vms_debug (3, "prologue\n");
+#endif
+ break;
+
+ case DST_S_C_EPILOG:
+#if VMS_DEBUG
+ _bfd_vms_debug (3, "epilog\n");
+#endif
+ break;
+
+ case DST_S_C_BLKBEG:
+#if VMS_DEBUG
+ _bfd_vms_debug (3, "block\n");
+#endif
+ break;
+
+ case DST_S_C_BLKEND:
+#if VMS_DEBUG
+ _bfd_vms_debug (3, "end block\n");
+#endif
+ break;
+
+ case DST_S_C_SOURCE:
+ src_ptr = ptr + DST_S_C_SOURCE_HEADER_SIZE;
+
+#if VMS_DEBUG
+ _bfd_vms_debug (3, "source info\n");
+#endif
+
+ while (src_ptr < ptr + rec_length)
+ {
+ int cmd = src_ptr[0], cmd_length, data;
+
+ switch (cmd)
+ {
+ case DST_S_C_SRC_DECLFILE:
+ {
+ unsigned int fileid
+ = bfd_getl16 (src_ptr + DST_S_W_SRC_DF_FILEID);
+ char *filename
+ = _bfd_vms_save_counted_string (src_ptr
+ + DST_S_B_SRC_DF_FILENAME);
+
+ while (fileid >= module->file_table_count)
+ {
+ module->file_table_count *= 2;
+ module->file_table
+ = bfd_realloc (module->file_table,
+ module->file_table_count
+ * sizeof (struct fileinfo));
+ }
+
+ module->file_table [fileid].name = filename;
+ module->file_table [fileid].srec = 1;
+ cmd_length = src_ptr[DST_S_B_SRC_DF_LENGTH] + 2;
+#if VMS_DEBUG
+ _bfd_vms_debug (4, "DST_S_C_SRC_DECLFILE: %d, %s\n",
+ fileid,
+ module->file_table [fileid].name);
+#endif
+ }
+ break;
+
+ case DST_S_C_SRC_DEFLINES_B:
+ /* Perform the association and set the next higher index
+ to the limit. */
+ data = src_ptr[DST_S_B_SRC_UNSBYTE];
+ srec = (struct srecinfo *)
+ bfd_zalloc (abfd, sizeof (struct srecinfo));
+ srec->line = curr_srec->line + data;
+ srec->srec = curr_srec->srec + data;
+ srec->sfile = curr_srec->sfile;
+ curr_srec->next = srec;
+ curr_srec = srec;
+ cmd_length = 2;
+#if VMS_DEBUG
+ _bfd_vms_debug (4, "DST_S_C_SRC_DEFLINES_B: %d\n", data);
+#endif
+ break;
+
+ case DST_S_C_SRC_DEFLINES_W:
+ /* Perform the association and set the next higher index
+ to the limit. */
+ data = bfd_getl16 (src_ptr + DST_S_W_SRC_UNSWORD);
+ srec = (struct srecinfo *)
+ bfd_zalloc (abfd, sizeof (struct srecinfo));
+ srec->line = curr_srec->line + data;
+ srec->srec = curr_srec->srec + data,
+ srec->sfile = curr_srec->sfile;
+ curr_srec->next = srec;
+ curr_srec = srec;
+ cmd_length = 3;
+#if VMS_DEBUG
+ _bfd_vms_debug (4, "DST_S_C_SRC_DEFLINES_W: %d\n", data);
+#endif
+ break;
+
+ case DST_S_C_SRC_INCRLNUM_B:
+ data = src_ptr[DST_S_B_SRC_UNSBYTE];
+ curr_srec->line += data;
+ cmd_length = 2;
+#if VMS_DEBUG
+ _bfd_vms_debug (4, "DST_S_C_SRC_INCRLNUM_B: %d\n", data);
+#endif
+ break;
+
+ case DST_S_C_SRC_SETFILE:
+ data = bfd_getl16 (src_ptr + DST_S_W_SRC_UNSWORD);
+ curr_srec->sfile = data;
+ curr_srec->srec = module->file_table[data].srec;
+ cmd_length = 3;
+#if VMS_DEBUG
+ _bfd_vms_debug (4, "DST_S_C_SRC_SETFILE: %d\n", data);
+#endif
+ break;
+
+ case DST_S_C_SRC_SETLNUM_L:
+ data = bfd_getl32 (src_ptr + DST_S_L_SRC_UNSLONG);
+ curr_srec->line = data;
+ cmd_length = 5;
+#if VMS_DEBUG
+ _bfd_vms_debug (4, "DST_S_C_SRC_SETLNUM_L: %d\n", data);
+#endif
+ break;
+
+ case DST_S_C_SRC_SETLNUM_W:
+ data = bfd_getl16 (src_ptr + DST_S_W_SRC_UNSWORD);
+ curr_srec->line = data;
+ cmd_length = 3;
+#if VMS_DEBUG
+ _bfd_vms_debug (4, "DST_S_C_SRC_SETLNUM_W: %d\n", data);
+#endif
+ break;
+
+ case DST_S_C_SRC_SETREC_L:
+ data = bfd_getl32 (src_ptr + DST_S_L_SRC_UNSLONG);
+ curr_srec->srec = data;
+ module->file_table[curr_srec->sfile].srec = data;
+ cmd_length = 5;
+#if VMS_DEBUG
+ _bfd_vms_debug (4, "DST_S_C_SRC_SETREC_L: %d\n", data);
+#endif
+ break;
+
+ case DST_S_C_SRC_SETREC_W:
+ data = bfd_getl16 (src_ptr + DST_S_W_SRC_UNSWORD);
+ curr_srec->srec = data;
+ module->file_table[curr_srec->sfile].srec = data;
+ cmd_length = 3;
+#if VMS_DEBUG
+ _bfd_vms_debug (4, "DST_S_C_SRC_SETREC_W: %d\n", data);
+#endif
+ break;
+
+ case DST_S_C_SRC_FORMFEED:
+ cmd_length = 1;
+#if VMS_DEBUG
+ _bfd_vms_debug (4, "DST_S_C_SRC_FORMFEED\n");
+#endif
+ break;
+
+ default:
+ (*_bfd_error_handler) (_("unknown source command %d"),
+ cmd);
+ cmd_length = 2;
+ break;
+ }
+
+ src_ptr += cmd_length;
+ }
+ break;
+
+ case DST_S_C_LINE_NUM:
+ pcl_ptr = ptr + DST_S_C_LINE_NUM_HEADER_SIZE;
+
+#if VMS_DEBUG
+ _bfd_vms_debug (3, "line info\n");
+#endif
+
+ while (pcl_ptr < ptr + rec_length)
+ {
+ /* The command byte is signed so we must sign-extend it. */
+ int cmd = ((signed char *)pcl_ptr)[0], cmd_length, data;
+
+ switch (cmd)
+ {
+ case DST_S_C_DELTA_PC_W:
+ data = bfd_getl16 (pcl_ptr + DST_S_W_PCLINE_UNSWORD);
+ curr_pc += data;
+ curr_linenum += 1;
+ cmd_length = 3;
+#if VMS_DEBUG
+ _bfd_vms_debug (4, "DST_S_C_DELTA_PC_W: %d\n", data);
+#endif
+ break;
+
+ case DST_S_C_DELTA_PC_L:
+ data = bfd_getl32 (pcl_ptr + DST_S_L_PCLINE_UNSLONG);
+ curr_pc += data;
+ curr_linenum += 1;
+ cmd_length = 5;
+#if VMS_DEBUG
+ _bfd_vms_debug (4, "DST_S_C_DELTA_PC_L: %d\n", data);
+#endif
+ break;
+
+ case DST_S_C_INCR_LINUM:
+ data = pcl_ptr[DST_S_B_PCLINE_UNSBYTE];
+ curr_linenum += data;
+ cmd_length = 2;
+#if VMS_DEBUG
+ _bfd_vms_debug (4, "DST_S_C_INCR_LINUM: %d\n", data);
+#endif
+ break;
+
+ case DST_S_C_INCR_LINUM_W:
+ data = bfd_getl16 (pcl_ptr + DST_S_W_PCLINE_UNSWORD);
+ curr_linenum += data;
+ cmd_length = 3;
+#if VMS_DEBUG
+ _bfd_vms_debug (4, "DST_S_C_INCR_LINUM_W: %d\n", data);
+#endif
+ break;
+
+ case DST_S_C_INCR_LINUM_L:
+ data = bfd_getl32 (pcl_ptr + DST_S_L_PCLINE_UNSLONG);
+ curr_linenum += data;
+ cmd_length = 5;
+#if VMS_DEBUG
+ _bfd_vms_debug (4, "DST_S_C_INCR_LINUM_L: %d\n", data);
+#endif
+ break;
+
+ case DST_S_C_SET_LINUM_INCR:
+ (*_bfd_error_handler)
+ (_("DST_S_C_SET_LINUM_INCR not implemented"));
+ cmd_length = 2;
+ break;
+
+ case DST_S_C_SET_LINUM_INCR_W:
+ (*_bfd_error_handler)
+ (_("DST_S_C_SET_LINUM_INCR_W not implemented"));
+ cmd_length = 3;
+ break;
+
+ case DST_S_C_RESET_LINUM_INCR:
+ (*_bfd_error_handler)
+ (_("DST_S_C_RESET_LINUM_INCR not implemented"));
+ cmd_length = 1;
+ break;
+
+ case DST_S_C_BEG_STMT_MODE:
+ (*_bfd_error_handler)
+ (_("DST_S_C_BEG_STMT_MODE not implemented"));
+ cmd_length = 1;
+ break;
+
+ case DST_S_C_END_STMT_MODE:
+ (*_bfd_error_handler)
+ (_("DST_S_C_END_STMT_MODE not implemented"));
+ cmd_length = 1;
+ break;
+
+ case DST_S_C_SET_LINUM_B:
+ data = pcl_ptr[DST_S_B_PCLINE_UNSBYTE];
+ curr_linenum = data;
+ cmd_length = 2;
+#if VMS_DEBUG
+ _bfd_vms_debug (4, "DST_S_C_SET_LINUM_B: %d\n", data);
+#endif
+ break;
+
+ case DST_S_C_SET_LINE_NUM:
+ data = bfd_getl16 (pcl_ptr + DST_S_W_PCLINE_UNSWORD);
+ curr_linenum = data;
+ cmd_length = 3;
+#if VMS_DEBUG
+ _bfd_vms_debug (4, "DST_S_C_SET_LINE_NUM: %d\n", data);
+#endif
+ break;
+
+ case DST_S_C_SET_LINUM_L:
+ data = bfd_getl32 (pcl_ptr + DST_S_L_PCLINE_UNSLONG);
+ curr_linenum = data;
+ cmd_length = 5;
+#if VMS_DEBUG
+ _bfd_vms_debug (4, "DST_S_C_SET_LINUM_L: %d\n", data);
+#endif
+ break;
+
+ case DST_S_C_SET_PC:
+ (*_bfd_error_handler)
+ (_("DST_S_C_SET_PC not implemented"));
+ cmd_length = 2;
+ break;
+
+ case DST_S_C_SET_PC_W:
+ (*_bfd_error_handler)
+ (_("DST_S_C_SET_PC_W not implemented"));
+ cmd_length = 3;
+ break;
+
+ case DST_S_C_SET_PC_L:
+ (*_bfd_error_handler)
+ (_("DST_S_C_SET_PC_L not implemented"));
+ cmd_length = 5;
+ break;
+
+ case DST_S_C_SET_STMTNUM:
+ (*_bfd_error_handler)
+ (_("DST_S_C_SET_STMTNUM not implemented"));
+ cmd_length = 2;
+ break;
+
+ case DST_S_C_TERM:
+ data = pcl_ptr[DST_S_B_PCLINE_UNSBYTE];
+ curr_pc += data;
+ cmd_length = 2;
+#if VMS_DEBUG
+ _bfd_vms_debug (4, "DST_S_C_TERM: %d\n", data);
+#endif
+ break;
+
+ case DST_S_C_TERM_W:
+ data = bfd_getl16 (pcl_ptr + DST_S_W_PCLINE_UNSWORD);
+ curr_pc += data;
+ cmd_length = 3;
+#if VMS_DEBUG
+ _bfd_vms_debug (4, "DST_S_C_TERM_W: %d\n", data);
+#endif
+ break;
+
+ case DST_S_C_TERM_L:
+ data = bfd_getl32 (pcl_ptr + DST_S_L_PCLINE_UNSLONG);
+ curr_pc += data;
+ cmd_length = 5;
+#if VMS_DEBUG
+ _bfd_vms_debug (4, "DST_S_C_TERM_L: %d\n", data);
+#endif
+ break;
+
+ case DST_S_C_SET_ABS_PC:
+ data = bfd_getl32 (pcl_ptr + DST_S_L_PCLINE_UNSLONG);
+ curr_pc = data;
+ cmd_length = 5;
+#if VMS_DEBUG
+ _bfd_vms_debug (4, "DST_S_C_SET_ABS_PC: 0x%x\n", data);
+#endif
+ break;
+
+ default:
+ if (cmd <= 0)
+ {
+ curr_pc -= cmd;
+ curr_linenum += 1;
+ cmd_length = 1;
+#if VMS_DEBUG
+ _bfd_vms_debug (4, "bump pc to 0x%llx and line to %d\n",
+ curr_pc, curr_linenum);
+#endif
+ }
+ else
+ {
+ (*_bfd_error_handler) (_("unknown line command %d"),
+ cmd);
+ cmd_length = 2;
+ }
+ break;
+ }
+
+ if ((curr_linenum != prev_linum && curr_pc != prev_pc)
+ || cmd <= 0
+ || cmd == DST_S_C_DELTA_PC_L
+ || cmd == DST_S_C_DELTA_PC_W)
+ {
+ line = (struct lineinfo *)
+ bfd_zalloc (abfd, sizeof (struct lineinfo));
+ line->address = curr_pc;
+ line->line = curr_linenum;
+
+ curr_line->next = line;
+ curr_line = line;
+
+ prev_linum = curr_linenum;
+ prev_pc = curr_pc;
+#if VMS_DEBUG
+ _bfd_vms_debug (4, "-> correlate pc 0x%llx with line %d\n",
+ curr_pc, curr_linenum);
+#endif
+ }
+
+ pcl_ptr += cmd_length;
+ }
+ break;
+
+ case 0x17: /* Undocumented type used by DEC C to declare equates. */
+#if VMS_DEBUG
+ _bfd_vms_debug (3, "undocumented type 0x17\n");
+#endif
+ break;
+
+ default:
+#if VMS_DEBUG
+ _bfd_vms_debug (3, "ignoring record\n");
+#endif
+ break;
+
+ }
+
+ ptr += rec_length;
+ }
+
+ /* Finalize tables with EOL marker. */
+ srec = (struct srecinfo *) bfd_zalloc (abfd, sizeof (struct srecinfo));
+ srec->line = (unsigned int) -1;
+ srec->srec = (unsigned int) -1;
+ curr_srec->next = srec;
+
+ line = (struct lineinfo *) bfd_zalloc (abfd, sizeof (struct lineinfo));
+ line->line = (unsigned int) -1;
+ line->address = (bfd_vma) -1;
+ curr_line->next = line;
+
+ /* Advertise that this module has been parsed. This is needed
+ because parsing can be either performed at module creation
+ or deferred until debug info is consumed. */
+ SET_MODULE_PARSED (module);
+}
+
+/* Build the list of modules for the specified BFD. */
+
+static struct module *
+build_module_list (bfd *abfd)
+{
+ struct module *module, *list = NULL;
+ asection *dmt;
+
+ if ((dmt = bfd_get_section_by_name (abfd, "$DMT$")))
+ {
+ /* We have a DMT section so this must be an image. Parse the
+ section and build the list of modules. This is sufficient
+ since we can compute the start address and the end address
+ of every module from the section contents. */
+ bfd_size_type size = bfd_get_section_size (dmt);
+ unsigned char *ptr, *end;
+
+ ptr = (unsigned char *) bfd_alloc (abfd, size);
+ if (! ptr)
+ return NULL;
+
+ if (! bfd_get_section_contents (abfd, dmt, ptr, 0, size))
+ return NULL;
+
+#if VMS_DEBUG
+ _bfd_vms_debug (2, "DMT\n");
+#endif
+
+ end = ptr + size;
+
+ while (ptr < end)
+ {
+ /* Each header declares a module with its start offset and size
+ of debug info in the DST section, as well as the count of
+ program sections (i.e. address spans) it contains. */
+ int modbeg = bfd_getl32 (ptr + DBG_S_L_DMT_MODBEG);
+ int size = bfd_getl32 (ptr + DBG_S_L_DST_SIZE);
+ int count = bfd_getl16 (ptr + DBG_S_W_DMT_PSECT_COUNT);
+ ptr += DBG_S_C_DMT_HEADER_SIZE;
+
+#if VMS_DEBUG
+ _bfd_vms_debug (3, "module: modbeg = %d, size = %d, count = %d\n",
+ modbeg, size, count);
+#endif
+
+ /* We create a 'module' structure for each program section since
+ we only support contiguous addresses in a 'module' structure.
+ As a consequence, the actual debug info in the DST section is
+ shared and can be parsed multiple times; that doesn't seem to
+ cause problems in practice. */
+ while (count-- > 0)
+ {
+ int start = bfd_getl32 (ptr + DBG_S_L_DMT_PSECT_START);
+ int length = bfd_getl32 (ptr + DBG_S_L_DMT_PSECT_LENGTH);
+ module = new_module (abfd);
+ module->modbeg = modbeg;
+ module->size = size;
+ module->low = start;
+ module->high = start + length;
+ module->next = list;
+ list = module;
+ ptr += DBG_S_C_DMT_PSECT_SIZE;
+
+#if VMS_DEBUG
+ _bfd_vms_debug (4, "section: start = 0x%x, length = %d\n",
+ start, length);
+#endif
+ }
+ }
+ }
+ else
+ {
+ /* We don't have a DMT section so this must be an object. Parse
+ the module right now in order to compute its start address and
+ end address. */
+ module = new_module (abfd);
+ parse_module (abfd, module, PRIV (dst_section)->contents,
+ PRIV (dst_ptr_end) - PRIV (dst_section)->contents);
+ list = module;
+ }
+
+ return list;
+}
+
+/* Calculate and return the name of the source file and the line nearest
+ to the wanted location in the specified module. */
+
+static bfd_boolean
+module_find_nearest_line (bfd *abfd, struct module *module, bfd_vma addr,
+ const char **file, const char **func,
+ unsigned int *line)
+{
+ struct funcinfo *funcinfo;
+ struct lineinfo *lineinfo;
+ struct srecinfo *srecinfo;
+ bfd_boolean ret = FALSE;
+
+ /* Parse this module if that was not done at module creation. */
+ if (! IS_MODULE_PARSED (module))
+ {
+ unsigned int size = module->size;
+ unsigned int modbeg = PRIV (dst_section)->filepos + module->modbeg;
+ unsigned char *buffer = (unsigned char *) bfd_malloc (module->size);
+
+ if (bfd_seek (abfd, modbeg, SEEK_SET) != 0
+ || bfd_bread (buffer, size, abfd) != size)
+ {
+ bfd_set_error (bfd_error_no_debug_section);
+ return FALSE;
+ }
+
+ parse_module (abfd, module, buffer, size);
+ free (buffer);
+ }
+
+ /* Find out the function (if any) that contains the address. */
+ for (funcinfo = module->func_table; funcinfo; funcinfo = funcinfo->next)
+ if (addr >= funcinfo->low && addr <= funcinfo->high)
+ {
+ *func = funcinfo->name;
+ ret = TRUE;
+ break;
+ }
+
+ /* Find out the source file and the line nearest to the address. */
+ for (lineinfo = module->line_table; lineinfo; lineinfo = lineinfo->next)
+ if (lineinfo->next && addr < lineinfo->next->address)
+ {
+ for (srecinfo = module->srec_table; srecinfo; srecinfo = srecinfo->next)
+ if (srecinfo->next && lineinfo->line < srecinfo->next->line)
+ {
+ if (srecinfo->sfile > 0)
+ {
+ *file = module->file_table[srecinfo->sfile].name;
+ *line = srecinfo->srec + lineinfo->line - srecinfo->line;
+ }
+ else
+ {
+ *file = module->name;
+ *line = lineinfo->line;
+ }
+ return TRUE;
+ }
+
+ break;
+ }
+
+ return ret;
+}
+
+/* Provided a BFD, a section and an offset into the section, calculate and
+ return the name of the source file and the line nearest to the wanted
+ location. */
+
+bfd_boolean
+_bfd_vms_find_nearest_dst_line (bfd *abfd, asection *section,
+ asymbol **symbols ATTRIBUTE_UNUSED,
+ bfd_vma offset, const char **file,
+ const char **func, unsigned int *line)
+{
+ struct module *module;
+
+ /* What address are we looking for? */
+ bfd_vma addr = section->vma + offset;
+
+ *file = NULL;
+ *func = NULL;
+ *line = 0;
+
+ if (PRIV (dst_section) == NULL)
+ return FALSE;
+
+ if (PRIV (modules) == NULL)
+ {
+ PRIV (modules) = build_module_list (abfd);
+ if (PRIV (modules) == NULL)
+ return FALSE;
+ }
+
+ for (module = PRIV (modules); module; module = module->next)
+ if (addr >= module->low && addr <= module->high)
+ return module_find_nearest_line (abfd, module, addr, file, func, line);
+
+ return FALSE;
+}
+
+/* Process EDBG/ETBT record.
+ Return 0 on success, -1 on error */
+
+static int
+vms_slurp_debug (bfd *abfd)
+{
+ if (PRIV (dst_section) == NULL)
+ {
+ /* We have no way to find out beforehand how much debug info there
+ is in an object file, so pick an initial amount and grow it as
+ needed later. */
+ flagword flags = SEC_HAS_CONTENTS | SEC_DEBUGGING | SEC_RELOC;
+ asection *section = bfd_make_section (abfd, "$DST$");
+ if (!section)
+ return -1;
+ section->size = 1024;
+ if (!bfd_set_section_flags (abfd, section, flags))
+ return -1;
+ section->contents = ((unsigned char *)
+ bfd_zmalloc (section->size));
+ if (section->contents == NULL)
+ return -1;
+ section->filepos = (unsigned int)-1;
+ PRIV (dst_section) = section;
+ }
+
+ PRIV (image_section) = PRIV (dst_section);
+ PRIV (image_ptr) = PRIV (dst_section)->contents;
+
+ return _bfd_vms_slurp_tir (abfd, EOBJ_S_C_ETIR);
+}
+
+/* Process DBG/EDBG record.
+ Return 0 on success, -1 on error. */
+
+int
+_bfd_vms_slurp_dbg (bfd *abfd, int objtype ATTRIBUTE_UNUSED)
+{
+#if VMS_DEBUG
+ _bfd_vms_debug (2, "DBG/EDBG\n");
+#endif
+
+ abfd->flags |= (HAS_DEBUG | HAS_LINENO);
+
+ return vms_slurp_debug (abfd);
+}
+
+/* Process TBT/ETBT record.
+ Return 0 on success, -1 on error. */
+
+int
+_bfd_vms_slurp_tbt (bfd *abfd, int objtype ATTRIBUTE_UNUSED)
+{
+#if VMS_DEBUG
+ _bfd_vms_debug (2, "TBT/ETBT\n");
+#endif
+
+ abfd->flags |= HAS_LINENO;
+
+ return vms_slurp_debug (abfd);
+}
+
+/* Write DBG/EDBG record. */
+
+int
+_bfd_vms_write_dbg (bfd *abfd ATTRIBUTE_UNUSED, int objtype ATTRIBUTE_UNUSED)
+{
+#if VMS_DEBUG
+ _bfd_vms_debug (2, "vms_write_dbg (%p, objtype)\n", abfd, objtype);
+#endif
+
+ return 0;
+}
+
+/* Write TBT/ETBT record. */
+
+int
+_bfd_vms_write_tbt (bfd *abfd ATTRIBUTE_UNUSED, int objtype ATTRIBUTE_UNUSED)
+{
+#if VMS_DEBUG
+ _bfd_vms_debug (2, "vms_write_tbt (%p, %d)\n", abfd, objtype);
+#endif
+
+ return 0;
+}