Line 1... |
Line 1... |
/* vms-hdr.c -- BFD back-end for VMS/VAX (openVMS/VAX) and
|
/* vms-hdr.c -- BFD back-end for VMS/VAX (openVMS/VAX) and
|
EVAX (openVMS/Alpha) files.
|
EVAX (openVMS/Alpha) files.
|
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006,
|
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
|
HDR record handling functions
|
EMH record handling functions
|
EMH record handling functions
|
and
|
|
EOM record handling functions
|
EOM record handling functions
|
EEOM 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)
|
Written by Klaus K"ampf (kkaempf@rmi.de)
|
|
|
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
the Free Software Foundation; either version 3 of the License, or
|
the Free Software Foundation; either version 3 of the License, or
|
Line 33... |
Line 50... |
#include "safe-ctype.h"
|
#include "safe-ctype.h"
|
#include "libbfd.h"
|
#include "libbfd.h"
|
|
|
#include "vms.h"
|
#include "vms.h"
|
|
|
#ifdef HAVE_ALLOCA_H
|
static struct module *new_module (bfd *);
|
#include <alloca.h>
|
static void parse_module
|
#endif
|
(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
|
/* Read & process emh record
|
return 0 on success, -1 on error. */
|
return 0 on success, -1 on error. */
|
|
|
int
|
int
|
Line 83... |
Line 110... |
ptr += *ptr + 1;
|
ptr += *ptr + 1;
|
PRIV (hdr_data).hdr_t_date = _bfd_vms_save_sized_string (ptr, 17);
|
PRIV (hdr_data).hdr_t_date = _bfd_vms_save_sized_string (ptr, 17);
|
break;
|
break;
|
|
|
case MHD_S_C_LNM:
|
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;
|
break;
|
|
|
case MHD_S_C_SRC:
|
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;
|
break;
|
|
|
case MHD_S_C_TTL:
|
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;
|
break;
|
|
|
case EMH_S_C_MHD + EVAX_OFFSET:
|
case EMH_S_C_MHD + EVAX_OFFSET:
|
/* Module header. */
|
/* Module header. */
|
PRIV (hdr_data).hdr_b_strlvl = vms_rec[6];
|
PRIV (hdr_data).hdr_b_strlvl = vms_rec[6];
|
Line 108... |
Line 135... |
ptr += *ptr + 1;
|
ptr += *ptr + 1;
|
PRIV (hdr_data).hdr_t_date = _bfd_vms_save_sized_string (ptr, 17);
|
PRIV (hdr_data).hdr_t_date = _bfd_vms_save_sized_string (ptr, 17);
|
break;
|
break;
|
|
|
case EMH_S_C_LNM + EVAX_OFFSET:
|
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;
|
break;
|
|
|
case EMH_S_C_SRC + EVAX_OFFSET:
|
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;
|
break;
|
|
|
case EMH_S_C_TTL + EVAX_OFFSET:
|
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;
|
break;
|
|
|
case MHD_S_C_CPR:
|
case MHD_S_C_CPR:
|
case MHD_S_C_MTC:
|
case MHD_S_C_MTC:
|
case MHD_S_C_GTX:
|
case MHD_S_C_GTX:
|
Line 187... |
Line 214... |
{
|
{
|
asymbol *symbol;
|
asymbol *symbol;
|
unsigned int symnum;
|
unsigned int symnum;
|
int had_case = 0;
|
int had_case = 0;
|
int had_file = 0;
|
int had_file = 0;
|
|
char version [256];
|
|
|
#if VMS_DEBUG
|
#if VMS_DEBUG
|
vms_debug (2, "vms_write_hdr (%p)\n", abfd);
|
vms_debug (2, "vms_write_hdr (%p)\n", abfd);
|
#endif
|
#endif
|
|
|
Line 210... |
Line 238... |
{
|
{
|
/* Strip path and suffix information. */
|
/* Strip path and suffix information. */
|
char *fname, *fout, *fptr;
|
char *fname, *fout, *fptr;
|
|
|
fptr = bfd_get_filename (abfd);
|
fptr = bfd_get_filename (abfd);
|
fname = alloca (strlen (fptr) + 1);
|
fname = strdup (fptr);
|
strcpy (fname, fptr);
|
|
|
/* Strip VMS path. */
|
fout = strrchr (fname, ']');
|
fout = strrchr (fname, ']');
|
if (fout == 0)
|
if (fout == NULL)
|
fout = strchr (fname, ':');
|
fout = strchr (fname, ':');
|
if (fout != 0)
|
if (fout != NULL)
|
fout++;
|
fout++;
|
else
|
else
|
fout = fname;
|
fout = fname;
|
|
|
|
/* Strip UNIX path. */
|
|
fptr = strrchr (fout, '/');
|
|
if (fptr != NULL)
|
|
fout = fptr + 1;
|
|
|
/* Strip .obj suffix. */
|
/* Strip .obj suffix. */
|
fptr = strrchr (fname, '.');
|
fptr = strrchr (fout, '.');
|
if ((fptr != 0)
|
if (fptr != 0 && strcasecmp (fptr, ".OBJ") == 0)
|
&& (strcasecmp (fptr, ".OBJ") == 0))
|
|
*fptr = 0;
|
*fptr = 0;
|
|
|
|
/* Convert to upper case and truncate at 31 characters.
|
|
(VMS object file format restricts module name length to 31). */
|
fptr = fout;
|
fptr = fout;
|
while (*fptr != 0)
|
while (*fptr != 0)
|
{
|
{
|
*fptr = TOUPPER (*fptr);
|
*fptr = TOUPPER (*fptr);
|
fptr++;
|
fptr++;
|
if ((*fptr == ';')
|
if (*fptr == ';' || (fptr - fout) >= 31)
|
|| ((fptr - fout) > 31))
|
|
*fptr = 0;
|
*fptr = 0;
|
}
|
}
|
_bfd_vms_output_counted (abfd, fout);
|
_bfd_vms_output_counted (abfd, fout);
|
|
free (fname);
|
}
|
}
|
else
|
else
|
_bfd_vms_output_counted (abfd, "NONAME");
|
_bfd_vms_output_counted (abfd, "NONAME");
|
|
|
_bfd_vms_output_counted (abfd, BFD_VERSION_STRING);
|
_bfd_vms_output_counted (abfd, BFD_VERSION_STRING);
|
_bfd_vms_output_dump (abfd, get_vms_time_string (), 17);
|
_bfd_vms_output_dump (abfd, get_vms_time_string (), EMH_DATE_LENGTH);
|
_bfd_vms_output_fill (abfd, 0, 17);
|
_bfd_vms_output_fill (abfd, 0, EMH_DATE_LENGTH);
|
_bfd_vms_output_flush (abfd);
|
_bfd_vms_output_flush (abfd);
|
|
|
/* LMN. */
|
/* LMN. */
|
_bfd_vms_output_begin (abfd, EOBJ_S_C_EMH, EMH_S_C_LNM);
|
_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);
|
_bfd_vms_output_flush (abfd);
|
|
|
/* SRC. */
|
/* SRC. */
|
_bfd_vms_output_begin (abfd, EOBJ_S_C_EMH, EMH_S_C_SRC);
|
_bfd_vms_output_begin (abfd, EOBJ_S_C_EMH, EMH_S_C_SRC);
|
|
|
Line 318... |
Line 354... |
|| (objtype == OBJ_S_C_EOMW))
|
|| (objtype == OBJ_S_C_EOMW))
|
{
|
{
|
}
|
}
|
else
|
else
|
{
|
{
|
PRIV (eom_data).eom_l_total_lps = bfd_getl32 (vms_rec + 4);
|
PRIV (eom_data).eom_l_total_lps
|
PRIV (eom_data).eom_b_comcod = *(vms_rec + 8);
|
= 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_b_comcod > 1)
|
if (PRIV (eom_data).eom_w_comcod > 1)
|
{
|
{
|
(*_bfd_error_handler) (_("Object module NOT error-free !\n"));
|
(*_bfd_error_handler) (_("Object module NOT error-free !\n"));
|
bfd_set_error (bfd_error_bad_value);
|
bfd_set_error (bfd_error_bad_value);
|
return -1;
|
return -1;
|
}
|
}
|
PRIV (eom_data).eom_has_transfer = FALSE;
|
PRIV (eom_data).eom_has_transfer = FALSE;
|
if (PRIV (rec_size) > 10)
|
if (PRIV (rec_size) > 10)
|
{
|
{
|
PRIV (eom_data).eom_has_transfer = TRUE;
|
PRIV (eom_data).eom_has_transfer = TRUE;
|
PRIV (eom_data).eom_b_tfrflg = *(vms_rec + 9);
|
PRIV (eom_data).eom_b_tfrflg = vms_rec[EEOM_S_B_TFRFLG];
|
PRIV (eom_data).eom_l_psindx = bfd_getl32 (vms_rec + 12);
|
PRIV (eom_data).eom_l_psindx
|
PRIV (eom_data).eom_l_tfradr = bfd_getl32 (vms_rec + 16);
|
= 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;
|
abfd->start_address = PRIV (eom_data).eom_l_tfradr;
|
}
|
}
|
}
|
}
|
return 0;
|
return 0;
|
Line 376... |
Line 414... |
|
|
_bfd_vms_output_end (abfd);
|
_bfd_vms_output_end (abfd);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
No newline at end of file
|
No newline at end of file
|
|
/* 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;
|
|
}
|
|
|
No newline at end of file
|
No newline at end of file
|