hp-psymtab-read.c   [plain text]


/* Read hp debug symbols and convert to internal format, for GDB.
   Copyright 1993, 1996, 1998, 1999 Free Software Foundation, Inc.

   This file is part of GDB.

   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
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.

   Written by the Center for Software Science at the University of Utah
   and by Cygnus Support.  */

/* Common include file for hp_symtab_read.c and hp_psymtab_read.c.
   This has nested includes of a bunch of stuff. */
#include "hpread.h"
#include "demangle.h"

/* To generate dumping code, uncomment this define.  The dumping
   itself is controlled by routine-local statics called "dumping". */
/* #define DUMPING         1 */

/* To use the quick look-up tables, uncomment this define. */
#define QUICK_LOOK_UP      1

/* To call PXDB to process un-processed files, uncomment this define. */
#define USE_PXDB           1

/* Forward procedure declarations */

void hpread_symfile_init (struct objfile *);

void do_pxdb (bfd *);

void hpread_build_psymtabs (struct objfile *, int);

void hpread_symfile_finish (struct objfile *);

static union dnttentry *hpread_get_gntt (int, struct objfile *);

static unsigned long hpread_get_textlow (int, int, struct objfile *, int);

static struct partial_symtab *hpread_start_psymtab
  (struct objfile *, char *, CORE_ADDR, int,
   struct partial_symbol **, struct partial_symbol **);

static struct partial_symtab *hpread_end_psymtab
  (struct partial_symtab *, char **, int, int, CORE_ADDR,
   struct partial_symtab **, int);

/* End of forward routine declarations */

#ifdef USE_PXDB

/* NOTE use of system files!  May not be portable. */

#define PXDB_SVR4 "/opt/langtools/bin/pxdb"
#define PXDB_BSD  "/usr/bin/pxdb"

#include <stdlib.h>
#include <string.h>

/* check for the existence of a file, given its full pathname */
int
file_exists (char *filename)
{
  if (filename)
    return (access (filename, F_OK) == 0);
  return 0;
}


/* Translate from the "hp_language" enumeration in hp-symtab.h
   used in the debug info to gdb's generic enumeration in defs.h. */
static enum language
trans_lang (enum hp_language in_lang)
{
  if (in_lang == HP_LANGUAGE_C)
    return language_c;

  else if (in_lang == HP_LANGUAGE_CPLUSPLUS)
    return language_cplus;

  else if (in_lang == HP_LANGUAGE_FORTRAN)
    return language_fortran;

  else
    return language_unknown;
}

static char main_string[] = "main";

/* Call PXDB to process our file.

   Approach copied from DDE's "dbgk_run_pxdb".  Note: we
   don't check for BSD location of pxdb, nor for existence
   of pxdb itself, etc.

   NOTE: uses system function and string functions directly.

   Return value: 1 if ok, 0 if not */
int
hpread_call_pxdb (char *file_name)
{
  char *p;
  int status;
  int retval;

  if (file_exists (PXDB_SVR4))
    {
      p = malloc (strlen (PXDB_SVR4) + strlen (file_name) + 2);
      strcpy (p, PXDB_SVR4);
      strcat (p, " ");
      strcat (p, file_name);

      warning ("File not processed by pxdb--about to process now.\n");
      status = system (p);

      retval = (status == 0);
    }
  else
    {
      warning ("pxdb not found at standard location: /opt/langtools/bin\ngdb will not be able to debug %s.\nPlease install pxdb at the above location and then restart gdb.\nYou can also run pxdb on %s with the command\n\"pxdb %s\" and then restart gdb.", file_name, file_name, file_name);

      retval = 0;
    }
  return retval;
}				/* hpread_call_pxdb */


/* Return 1 if the file turns out to need pre-processing
   by PXDB, and we have thus called PXDB to do this processing
   and the file therefore needs to be re-loaded.  Otherwise
   return 0. */
int
hpread_pxdb_needed (bfd *sym_bfd)
{
  asection *pinfo_section, *debug_section, *header_section;
  unsigned int do_pxdb;
  char *buf;
  bfd_size_type header_section_size;

  unsigned long tmp;
  unsigned int pxdbed;

  header_section = bfd_get_section_by_name (sym_bfd, "$HEADER$");
  if (!header_section)
    {
      return 0;			/* No header at all, can't recover... */
    }

  debug_section = bfd_get_section_by_name (sym_bfd, "$DEBUG$");
  pinfo_section = bfd_get_section_by_name (sym_bfd, "$PINFO$");

  if (pinfo_section && !debug_section)
    {
      /* Debug info with DOC, has different header format. 
         this only happens if the file was pxdbed and compiled optimized
         otherwise the PINFO section is not there. */
      header_section_size = bfd_section_size (objfile->obfd, header_section);

      if (header_section_size == (bfd_size_type) sizeof (DOC_info_PXDB_header))
	{
	  buf = alloca (sizeof (DOC_info_PXDB_header));

	  if (!bfd_get_section_contents (sym_bfd,
					 header_section,
					 buf, 0,
					 header_section_size))
	    error ("bfd_get_section_contents\n");

	  tmp = bfd_get_32 (sym_bfd, (bfd_byte *) (buf + sizeof (int) * 4));
	  pxdbed = (tmp >> 31) & 0x1;

	  if (!pxdbed)
	    error ("file debug header info invalid\n");
	  do_pxdb = 0;
	}

      else
	error ("invalid $HEADER$ size in executable \n");
    }

  else
    {

      /* this can be three different cases:
         1. pxdbed and not doc
         - DEBUG and HEADER sections are there
         - header is PXDB_header type
         - pxdbed flag is set to 1

         2. not pxdbed and doc
         - DEBUG and HEADER  sections are there
         - header is DOC_info_header type
         - pxdbed flag is set to 0

         3. not pxdbed and not doc
         - DEBUG and HEADER sections are there
         - header is XDB_header type
         - pxdbed flag is set to 0

         NOTE: the pxdbed flag is meaningful also in the not
         already pxdb processed version of the header,
         because in case on non-already processed by pxdb files
         that same bit in the header would be always zero.
         Why? Because the bit is the leftmost bit of a word
         which contains a 'length' which is always a positive value
         so that bit is never set to 1 (otherwise it would be negative)

         Given the above, we have two choices : either we ignore the
         size of the header itself and just look at the pxdbed field,
         or we check the size and then we (for safety and paranoia related
         issues) check the bit.
         The first solution is used by DDE, the second by PXDB itself.
         I am using the second one here, because I already wrote it,
         and it is the end of a long day.
         Also, using the first approach would still involve size issues
         because we need to read in the contents of the header section, and
         give the correct amount of stuff we want to read to the
         get_bfd_section_contents function.  */

      /* decide which case depending on the size of the header section.
         The size is as defined in hp-symtab.h  */

      header_section_size = bfd_section_size (objfile->obfd, header_section);

      if (header_section_size == (bfd_size_type) sizeof (PXDB_header))	/* pxdb and not doc */
	{

	  buf = alloca (sizeof (PXDB_header));
	  if (!bfd_get_section_contents (sym_bfd,
					 header_section,
					 buf, 0,
					 header_section_size))
	    error ("bfd_get_section_contents\n");

	  tmp = bfd_get_32 (sym_bfd, (bfd_byte *) (buf + sizeof (int) * 3));
	  pxdbed = (tmp >> 31) & 0x1;

	  if (pxdbed)
	    do_pxdb = 0;
	  else
	    error ("file debug header invalid\n");
	}
      else			/*not pxdbed and doc OR not pxdbed and non doc */
	do_pxdb = 1;
    }

  if (do_pxdb)
    {
      return 1;
    }
  else
    {
      return 0;
    }
}				/* hpread_pxdb_needed */

#endif

/* Check whether the file needs to be preprocessed by pxdb. 
   If so, call pxdb. */

void
do_pxdb (bfd *sym_bfd)
{
  /* The following code is HP-specific.  The "right" way of
     doing this is unknown, but we bet would involve a target-
     specific pre-file-load check using a generic mechanism. */

  /* This code will not be executed if the file is not in SOM
     format (i.e. if compiled with gcc) */
  if (hpread_pxdb_needed (sym_bfd))
    {
      /*This file has not been pre-processed. Preprocess now */

      if (hpread_call_pxdb (sym_bfd->filename))
	{
	  /* The call above has changed the on-disk file, 
	     we can close the file anyway, because the
	     symbols will be reread in when the target is run */
	  bfd_close (sym_bfd);
	}
    }
}



#ifdef QUICK_LOOK_UP

/* Code to handle quick lookup-tables follows. */


/* Some useful macros */
#define VALID_FILE(i)   ((i) < pxdb_header_p->fd_entries)
#define VALID_MODULE(i) ((i) < pxdb_header_p->md_entries)
#define VALID_PROC(i)   ((i) < pxdb_header_p->pd_entries)
#define VALID_CLASS(i)  ((i) < pxdb_header_p->cd_entries)

#define FILE_START(i)    (qFD[i].adrStart)
#define MODULE_START(i) (qMD[i].adrStart)
#define PROC_START(i)    (qPD[i].adrStart)

#define FILE_END(i)   (qFD[i].adrEnd)
#define MODULE_END(i) (qMD[i].adrEnd)
#define PROC_END(i)   (qPD[i].adrEnd)

#define FILE_ISYM(i)   (qFD[i].isym)
#define MODULE_ISYM(i) (qMD[i].isym)
#define PROC_ISYM(i)   (qPD[i].isym)

#define VALID_CURR_FILE    (curr_fd < pxdb_header_p->fd_entries)
#define VALID_CURR_MODULE  (curr_md < pxdb_header_p->md_entries)
#define VALID_CURR_PROC    (curr_pd < pxdb_header_p->pd_entries)
#define VALID_CURR_CLASS   (curr_cd < pxdb_header_p->cd_entries)

#define CURR_FILE_START     (qFD[curr_fd].adrStart)
#define CURR_MODULE_START   (qMD[curr_md].adrStart)
#define CURR_PROC_START     (qPD[curr_pd].adrStart)

#define CURR_FILE_END    (qFD[curr_fd].adrEnd)
#define CURR_MODULE_END  (qMD[curr_md].adrEnd)
#define CURR_PROC_END    (qPD[curr_pd].adrEnd)

#define CURR_FILE_ISYM    (qFD[curr_fd].isym)
#define CURR_MODULE_ISYM  (qMD[curr_md].isym)
#define CURR_PROC_ISYM    (qPD[curr_pd].isym)

#define TELL_OBJFILE                                      \
            do {                                          \
               if( !told_objfile ) {                      \
                   told_objfile = 1;                      \
                   warning ("\nIn object file \"%s\":\n", \
                            objfile->name);               \
               }                                          \
            } while (0)



/* Keeping track of the start/end symbol table (LNTT) indices of
   psymtabs created so far */

typedef struct
{
  int start;
  int end;
}
pst_syms_struct;

static pst_syms_struct *pst_syms_array = 0;

static pst_syms_count = 0;
static pst_syms_size = 0;

/* used by the TELL_OBJFILE macro */
static boolean told_objfile = 0;

/* Set up psymtab symbol index stuff */
static void
init_pst_syms (void)
{
  pst_syms_count = 0;
  pst_syms_size = 20;
  pst_syms_array = (pst_syms_struct *) xmalloc (20 * sizeof (pst_syms_struct));
}

/* Clean up psymtab symbol index stuff */
static void
clear_pst_syms (void)
{
  pst_syms_count = 0;
  pst_syms_size = 0;
  free (pst_syms_array);
  pst_syms_array = 0;
}

/* Add information about latest psymtab to symbol index table */
static void
record_pst_syms (int start_sym, int end_sym)
{
  if (++pst_syms_count > pst_syms_size)
    {
      pst_syms_array = (pst_syms_struct *) xrealloc (pst_syms_array,
			      2 * pst_syms_size * sizeof (pst_syms_struct));
      pst_syms_size *= 2;
    }
  pst_syms_array[pst_syms_count - 1].start = start_sym;
  pst_syms_array[pst_syms_count - 1].end = end_sym;
}

/* Find a suitable symbol table index which can serve as the upper
   bound of a psymtab that starts at INDEX

   This scans backwards in the psymtab symbol index table to find a
   "hole" in which the given index can fit.  This is a heuristic!!
   We don't search the entire table to check for multiple holes,
   we don't care about overlaps, etc. 

   Return 0 => not found */
static int
find_next_pst_start (int index)
{
  int i;

  for (i = pst_syms_count - 1; i >= 0; i--)
    if (pst_syms_array[i].end <= index)
      return (i == pst_syms_count - 1) ? 0 : pst_syms_array[i + 1].start - 1;

  if (pst_syms_array[0].start > index)
    return pst_syms_array[0].start - 1;

  return 0;
}



/* Utility functions to find the ending symbol index for a psymtab */

/* Find the next file entry that begins beyond INDEX, and return
   its starting symbol index - 1.
   QFD is the file table, CURR_FD is the file entry from where to start,
   PXDB_HEADER_P as in hpread_quick_traverse (to allow macros to work).

   Return 0 => not found */
static int
find_next_file_isym (int index, quick_file_entry *qFD, int curr_fd,
		     PXDB_header_ptr pxdb_header_p)
{
  while (VALID_CURR_FILE)
    {
      if (CURR_FILE_ISYM >= index)
	return CURR_FILE_ISYM - 1;
      curr_fd++;
    }
  return 0;
}

/* Find the next procedure entry that begins beyond INDEX, and return
   its starting symbol index - 1.
   QPD is the procedure table, CURR_PD is the proc entry from where to start,
   PXDB_HEADER_P as in hpread_quick_traverse (to allow macros to work).

   Return 0 => not found */
static int
find_next_proc_isym (int index, quick_procedure_entry *qPD, int curr_pd,
		     PXDB_header_ptr pxdb_header_p)
{
  while (VALID_CURR_PROC)
    {
      if (CURR_PROC_ISYM >= index)
	return CURR_PROC_ISYM - 1;
      curr_pd++;
    }
  return 0;
}

/* Find the next module entry that begins beyond INDEX, and return
   its starting symbol index - 1.
   QMD is the module table, CURR_MD is the modue entry from where to start,
   PXDB_HEADER_P as in hpread_quick_traverse (to allow macros to work).

   Return 0 => not found */
static int
find_next_module_isym (int index, quick_module_entry *qMD, int curr_md,
		       PXDB_header_ptr pxdb_header_p)
{
  while (VALID_CURR_MODULE)
    {
      if (CURR_MODULE_ISYM >= index)
	return CURR_MODULE_ISYM - 1;
      curr_md++;
    }
  return 0;
}

/* Scan and record partial symbols for all functions starting from index
   pointed to by CURR_PD_P, and between code addresses START_ADR and END_ADR.
   Other parameters are explained in comments below. */

/* This used to be inline in hpread_quick_traverse, but now that we do
   essentially the same thing for two different cases (modules and
   module-less files), it's better organized in a separate routine,
   although it does take lots of arguments.  pai/1997-10-08
   
   CURR_PD_P is the pointer to the current proc index. QPD is the
   procedure quick lookup table.  MAX_PROCS is the number of entries
   in the proc. table.  START_ADR is the beginning of the code range
   for the current psymtab.  end_adr is the end of the code range for
   the current psymtab.  PST is the current psymtab.  VT_bits is
   a pointer to the strings table of SOM debug space.  OBJFILE is
   the current object file. */

static int
scan_procs (int *curr_pd_p, quick_procedure_entry *qPD, int max_procs,
	    CORE_ADDR start_adr, CORE_ADDR end_adr, struct partial_symtab *pst,
	    char *vt_bits, struct objfile *objfile)
{
  union dnttentry *dn_bufp;
  int symbol_count = 0;		/* Total number of symbols in this psymtab */
  int curr_pd = *curr_pd_p;	/* Convenience variable -- avoid dereferencing pointer all the time */

#ifdef DUMPING
  /* Turn this on for lots of debugging information in this routine */
  static int dumping = 0;
#endif

#ifdef DUMPING
  if (dumping)
    {
      printf ("Scan_procs called, addresses %x to %x, proc %x\n", start_adr, end_adr, curr_pd);
    }
#endif

  while ((CURR_PROC_START <= end_adr) && (curr_pd < max_procs))
    {

      char *rtn_name;		/* mangled name */
      char *rtn_dem_name;	/* qualified demangled name */
      char *class_name;
      int class;

      if ((trans_lang ((enum hp_language) qPD[curr_pd].language) == language_cplus) &&
	  vt_bits[(long) qPD[curr_pd].sbAlias])		/* not a null string */
	{
	  /* Get mangled name for the procedure, and demangle it */
	  rtn_name = &vt_bits[(long) qPD[curr_pd].sbAlias];
	  rtn_dem_name = cplus_demangle (rtn_name, DMGL_ANSI | DMGL_PARAMS);
	}
      else
	{
	  rtn_name = &vt_bits[(long) qPD[curr_pd].sbProc];
	  rtn_dem_name = NULL;
	}

      /* Hack to get around HP C/C++ compilers' insistence on providing
         "_MAIN_" as an alternate name for "main" */
      if ((strcmp (rtn_name, "_MAIN_") == 0) &&
	  (strcmp (&vt_bits[(long) qPD[curr_pd].sbProc], "main") == 0))
	rtn_dem_name = rtn_name = main_string;

#ifdef DUMPING
      if (dumping)
	{
	  printf ("..add %s (demangled %s), index %x to this psymtab\n", rtn_name, rtn_dem_name, curr_pd);
	}
#endif

      /* Check for module-spanning routines. */
      if (CURR_PROC_END > end_adr)
	{
	  TELL_OBJFILE;
	  warning ("Procedure \"%s\" [0x%x] spans file or module boundaries.", rtn_name, curr_pd);
	}

      /* Add this routine symbol to the list in the objfile. 
         Unfortunately we have to go to the LNTT to determine the
         correct list to put it on. An alternative (which the
         code used to do) would be to not check and always throw
         it on the "static" list. But if we go that route, then
         symbol_lookup() needs to be tweaked a bit to account
         for the fact that the function might not be found on
         the correct list in the psymtab. - RT */
      dn_bufp = hpread_get_lntt (qPD[curr_pd].isym, objfile);
      if (dn_bufp->dfunc.global)
	add_psymbol_with_dem_name_to_list (rtn_name,
					   strlen (rtn_name),
					   rtn_dem_name,
					   strlen (rtn_dem_name),
					   VAR_NAMESPACE,
					   LOC_BLOCK,	/* "I am a routine"        */
					   &objfile->global_psymbols,
					   (qPD[curr_pd].adrStart +	/* Starting address of rtn */
				 ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile))),
					   0,	/* core addr?? */
		      trans_lang ((enum hp_language) qPD[curr_pd].language),
					   objfile);
      else
	add_psymbol_with_dem_name_to_list (rtn_name,
					   strlen (rtn_name),
					   rtn_dem_name,
					   strlen (rtn_dem_name),
					   VAR_NAMESPACE,
					   LOC_BLOCK,	/* "I am a routine"        */
					   &objfile->static_psymbols,
					   (qPD[curr_pd].adrStart +	/* Starting address of rtn */
				 ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile))),
					   0,	/* core addr?? */
		      trans_lang ((enum hp_language) qPD[curr_pd].language),
					   objfile);

      symbol_count++;
      *curr_pd_p = ++curr_pd;	/* bump up count & reflect in caller */
    }				/* loop over procedures */

#ifdef DUMPING
  if (dumping)
    {
      if (symbol_count == 0)
	printf ("Scan_procs: no symbols found!\n");
    }
#endif

  return symbol_count;
}


/* Traverse the quick look-up tables, building a set of psymtabs.

   This constructs a psymtab for modules and files in the quick lookup
   tables.

   Mostly, modules correspond to compilation units, so we try to
   create psymtabs that correspond to modules; however, in some cases
   a file can result in a compiled object which does not have a module
   entry for it, so in such cases we create a psymtab for the file.  */

int
hpread_quick_traverse (struct objfile *objfile, char *gntt_bits,
		       char *vt_bits, PXDB_header_ptr pxdb_header_p)
{
  struct partial_symtab *pst;

  char *addr;

  quick_procedure_entry *qPD;
  quick_file_entry *qFD;
  quick_module_entry *qMD;
  quick_class_entry *qCD;

  int idx;
  int i;
  CORE_ADDR start_adr;		/* current psymtab's starting code addr   */
  CORE_ADDR end_adr;		/* current psymtab's ending code addr     */
  CORE_ADDR next_mod_adr;	/* next module's starting code addr    */
  int curr_pd;			/* current procedure */
  int curr_fd;			/* current file      */
  int curr_md;			/* current module    */
  int start_sym;		/* current psymtab's starting symbol index */
  int end_sym;			/* current psymtab's ending symbol index   */
  int max_LNTT_sym_index;
  int syms_in_pst;
  B_TYPE *class_entered;

  struct partial_symbol **global_syms;	/* We'll be filling in the "global"   */
  struct partial_symbol **static_syms;	/* and "static" tables in the objfile
					   as we go, so we need a pair of     
					   current pointers. */

#ifdef DUMPING
  /* Turn this on for lots of debugging information in this routine.
     You get a blow-by-blow account of quick lookup table reading */
  static int dumping = 0;
#endif

  pst = (struct partial_symtab *) 0;

  /* Clear out some globals */
  init_pst_syms ();
  told_objfile = 0;

  /* Demangling style -- if EDG style already set, don't change it,
     as HP style causes some problems with the KAI EDG compiler */
  if (current_demangling_style != edg_demangling)
    {
      /* Otherwise, ensure that we are using HP style demangling */
      set_demangling_style (HP_DEMANGLING_STYLE_STRING);
    }

  /* First we need to find the starting points of the quick
     look-up tables in the GNTT. */

  addr = gntt_bits;

  qPD = (quick_procedure_entry_ptr) addr;
  addr += pxdb_header_p->pd_entries * sizeof (quick_procedure_entry);

#ifdef DUMPING
  if (dumping)
    {
      printf ("\n Printing routines as we see them\n");
      for (i = 0; VALID_PROC (i); i++)
	{
	  idx = (long) qPD[i].sbProc;
	  printf ("%s %x..%x\n", &vt_bits[idx],
		  (int) PROC_START (i),
		  (int) PROC_END (i));
	}
    }
#endif

  qFD = (quick_file_entry_ptr) addr;
  addr += pxdb_header_p->fd_entries * sizeof (quick_file_entry);

#ifdef DUMPING
  if (dumping)
    {
      printf ("\n Printing files as we see them\n");
      for (i = 0; VALID_FILE (i); i++)
	{
	  idx = (long) qFD[i].sbFile;
	  printf ("%s %x..%x\n", &vt_bits[idx],
		  (int) FILE_START (i),
		  (int) FILE_END (i));
	}
    }
#endif

  qMD = (quick_module_entry_ptr) addr;
  addr += pxdb_header_p->md_entries * sizeof (quick_module_entry);

#ifdef DUMPING
  if (dumping)
    {
      printf ("\n Printing modules as we see them\n");
      for (i = 0; i < pxdb_header_p->md_entries; i++)
	{
	  idx = (long) qMD[i].sbMod;
	  printf ("%s\n", &vt_bits[idx]);
	}
    }
#endif

  qCD = (quick_class_entry_ptr) addr;
  addr += pxdb_header_p->cd_entries * sizeof (quick_class_entry);

#ifdef DUMPING
  if (dumping)
    {
      printf ("\n Printing classes as we see them\n");
      for (i = 0; VALID_CLASS (i); i++)
	{
	  idx = (long) qCD[i].sbClass;
	  printf ("%s\n", &vt_bits[idx]);
	}

      printf ("\n Done with dump, on to build!\n");
    }
#endif

  /* We need this index only while hp-symtab-read.c expects
     a byte offset to the end of the LNTT entries for a given
     psymtab.  Thus the need for it should go away someday.

     When it goes away, then we won't have any need to load the
     LNTT from the objfile at psymtab-time, and start-up will be
     faster.  To make that work, we'll need some way to create
     a null pst for the "globals" pseudo-module. */
  max_LNTT_sym_index = LNTT_SYMCOUNT (objfile);

  /* Scan the module descriptors and make a psymtab for each.

     We know the MDs, FDs and the PDs are in order by starting
     address.  We use that fact to traverse all three arrays in
     parallel, knowing when the next PD is in a new file
     and we need to create a new psymtab. */
  curr_pd = 0;			/* Current procedure entry */
  curr_fd = 0;			/* Current file entry */
  curr_md = 0;			/* Current module entry */

  start_adr = 0;		/* Current psymtab code range */
  end_adr = 0;

  start_sym = 0;		/* Current psymtab symbol range */
  end_sym = 0;

  syms_in_pst = 0;		/* Symbol count for psymtab */

  /* Psts actually just have pointers into the objfile's
     symbol table, not their own symbol tables. */
  global_syms = objfile->global_psymbols.list;
  static_syms = objfile->static_psymbols.list;


  /* First skip over pseudo-entries with address 0.  These represent inlined
     routines and abstract (uninstantiated) template routines.
     FIXME: These should be read in and available -- even if we can't set
     breakpoints, etc., there's some information that can be presented
     to the user. pai/1997-10-08  */

  while (VALID_CURR_PROC && (CURR_PROC_START == 0))
    curr_pd++;

  /* Loop over files, modules, and procedures in code address order. Each
     time we enter an iteration of this loop, curr_pd points to the first
     unprocessed procedure, curr_fd points to the first unprocessed file, and
     curr_md to the first unprocessed module.  Each iteration of this loop
     updates these as required -- any or all of them may be bumpd up
     each time around.  When we exit this loop, we are done with all files
     and modules in the tables -- there may still be some procedures, however.

     Note: This code used to loop only over module entries, under the assumption
     that files can occur via inclusions and are thus unreliable, while a
     compiled object always corresponds to a module.  With CTTI in the HP aCC
     compiler, it turns out that compiled objects may have only files and no
     modules; so we have to loop over files and modules, creating psymtabs for
     either as appropriate.  Unfortunately there are some problems (notably:
     1. the lack of "SRC_FILE_END" entries in the LNTT, 2. the lack of pointers
     to the ending symbol indices of a module or a file) which make it quite hard
     to do this correctly.  Currently it uses a bunch of heuristics to start and
     end psymtabs; they seem to work well with most objects generated by aCC, but
     who knows when that will change...   */

  while (VALID_CURR_FILE || VALID_CURR_MODULE)
    {

      char *mod_name_string;
      char *full_name_string;

      /* First check for modules like "version.c", which have no code
         in them but still have qMD entries.  They also have no qFD or
         qPD entries.  Their start address is -1 and their end address
         is 0.  */
      if (VALID_CURR_MODULE && (CURR_MODULE_START == -1) && (CURR_MODULE_END == 0))
	{

	  mod_name_string = &vt_bits[(long) qMD[curr_md].sbMod];

#ifdef DUMPING
	  if (dumping)
	    printf ("Module with data only %s\n", mod_name_string);
#endif

	  /* We'll skip the rest (it makes error-checking easier), and
	     just make an empty pst.  Right now empty psts are not put
	     in the pst chain, so all this is for naught, but later it
	     might help.  */

	  pst = hpread_start_psymtab (objfile,
				      mod_name_string,
				      CURR_MODULE_START,	/* Low text address: bogus! */
		       (CURR_MODULE_ISYM * sizeof (struct dntt_type_block)),
	  /* ldsymoff */
				      global_syms,
				      static_syms);

	  pst = hpread_end_psymtab (pst,
				    NULL,	/* psymtab_include_list */
				    0,	/* includes_used        */
				  end_sym * sizeof (struct dntt_type_block),
	  /* byte index in LNTT of end 
	     = capping symbol offset  
	     = LDSYMOFF of nextfile */
				    0,	/* text high            */
				    NULL,	/* dependency_list      */
				    0);		/* dependencies_used    */

	  global_syms = objfile->global_psymbols.next;
	  static_syms = objfile->static_psymbols.next;

	  curr_md++;
	}
      else if (VALID_CURR_MODULE &&
	       ((CURR_MODULE_START == 0) || (CURR_MODULE_START == -1) ||
		(CURR_MODULE_END == 0) || (CURR_MODULE_END == -1)))
	{
	  TELL_OBJFILE;
	  warning ("Module \"%s\" [0x%x] has non-standard addresses.  It starts at 0x%x, ends at 0x%x, and will be skipped.",
		   mod_name_string, curr_md, start_adr, end_adr);
	  /* On to next module */
	  curr_md++;
	}
      else
	{
	  /* First check if we are looking at a file with code in it
	     that does not overlap the current module's code range */

	  if (VALID_CURR_FILE ? (VALID_CURR_MODULE ? (CURR_FILE_END < CURR_MODULE_START) : 1) : 0)
	    {

	      /* Looking at file not corresponding to any module,
	         create a psymtab for it */
	      full_name_string = &vt_bits[(long) qFD[curr_fd].sbFile];
	      start_adr = CURR_FILE_START;
	      end_adr = CURR_FILE_END;
	      start_sym = CURR_FILE_ISYM;

	      /* Check if there are any procedures not handled until now, that
	         begin before the start address of this file, and if so, adjust
	         this module's start address to include them.  This handles routines that
	         are in between file or module ranges for some reason (probably
	         indicates a compiler bug */

	      if (CURR_PROC_START < start_adr)
		{
		  TELL_OBJFILE;
		  warning ("Found procedure \"%s\" [0x%x] that is not in any file or module.",
			   &vt_bits[(long) qPD[curr_pd].sbProc], curr_pd);
		  start_adr = CURR_PROC_START;
		  if (CURR_PROC_ISYM < start_sym)
		    start_sym = CURR_PROC_ISYM;
		}

	      /* Sometimes (compiler bug -- COBOL) the module end address is higher
	         than the start address of the next module, so check for that and
	         adjust accordingly */

	      if (VALID_FILE (curr_fd + 1) && (FILE_START (curr_fd + 1) <= end_adr))
		{
		  TELL_OBJFILE;
		  warning ("File \"%s\" [0x%x] has ending address after starting address of next file; adjusting ending address down.",
			   full_name_string, curr_fd);
		  end_adr = FILE_START (curr_fd + 1) - 1;	/* Is -4 (or -8 for 64-bit) better? */
		}
	      if (VALID_MODULE (curr_md) && (CURR_MODULE_START <= end_adr))
		{
		  TELL_OBJFILE;
		  warning ("File \"%s\" [0x%x] has ending address after starting address of next module; adjusting ending address down.",
			   full_name_string, curr_fd);
		  end_adr = CURR_MODULE_START - 1;	/* Is -4 (or -8 for 64-bit) better? */
		}


#ifdef DUMPING
	      if (dumping)
		{
		  printf ("Make new psymtab for file %s (%x to %x).\n",
			  full_name_string, start_adr, end_adr);
		}
#endif
	      /* Create the basic psymtab, connecting it in the list
	         for this objfile and pointing its symbol entries
	         to the current end of the symbol areas in the objfile.

	         The "ldsymoff" parameter is the byte offset in the LNTT
	         of the first symbol in this file.  Some day we should
	         turn this into an index (fix in hp-symtab-read.c as well).
	         And it's not even the right byte offset, as we're using
	         the size of a union! FIXME!  */
	      pst = hpread_start_psymtab (objfile,
					  full_name_string,
					  start_adr,	/* Low text address */
			      (start_sym * sizeof (struct dntt_type_block)),
	      /* ldsymoff */
					  global_syms,
					  static_syms);

	      /* Set up to only enter each class referenced in this module once.  */
	      class_entered = malloc (B_BYTES (pxdb_header_p->cd_entries));
	      B_CLRALL (class_entered, pxdb_header_p->cd_entries);

	      /* Scan the procedure descriptors for procedures in the current
	         file, based on the starting addresses. */

	      syms_in_pst = scan_procs (&curr_pd, qPD, pxdb_header_p->pd_entries,
					start_adr, end_adr, pst, vt_bits, objfile);

	      /* Get ending symbol offset */

	      end_sym = 0;
	      /* First check for starting index before previous psymtab */
	      if (pst_syms_count && start_sym < pst_syms_array[pst_syms_count - 1].end)
		{
		  end_sym = find_next_pst_start (start_sym);
		}
	      /* Look for next start index of a file or module, or procedure */
	      if (!end_sym)
		{
		  int next_file_isym = find_next_file_isym (start_sym, qFD, curr_fd + 1, pxdb_header_p);
		  int next_module_isym = find_next_module_isym (start_sym, qMD, curr_md, pxdb_header_p);
		  int next_proc_isym = find_next_proc_isym (start_sym, qPD, curr_pd, pxdb_header_p);

		  if (next_file_isym && next_module_isym)
		    {
		      /* pick lower of next file or module start index */
		      end_sym = min (next_file_isym, next_module_isym);
		    }
		  else
		    {
		      /* one of them is zero, pick the other */
		      end_sym = max (next_file_isym, next_module_isym);
		    }

		  /* As a precaution, check next procedure index too */
		  if (!end_sym)
		    end_sym = next_proc_isym;
		  else
		    end_sym = min (end_sym, next_proc_isym);
		}

	      /* Couldn't find procedure, file, or module, use globals as default */
	      if (!end_sym)
		end_sym = pxdb_header_p->globals;

#ifdef DUMPING
	      if (dumping)
		{
		  printf ("File psymtab indices: %x to %x\n", start_sym, end_sym);
		}
#endif

	      pst = hpread_end_psymtab (pst,
					NULL,	/* psymtab_include_list */
					0,	/* includes_used        */
				  end_sym * sizeof (struct dntt_type_block),
	      /* byte index in LNTT of end 
	         = capping symbol offset   
	         = LDSYMOFF of nextfile */
					end_adr,	/* text high */
					NULL,	/* dependency_list */
					0);	/* dependencies_used */

	      record_pst_syms (start_sym, end_sym);

	      if (NULL == pst)
		warning ("No symbols in psymtab for file \"%s\" [0x%x].", full_name_string, curr_fd);

#ifdef DUMPING
	      if (dumping)
		{
		  printf ("Made new psymtab for file %s (%x to %x), sym %x to %x.\n",
			  full_name_string, start_adr, end_adr, CURR_FILE_ISYM, end_sym);
		}
#endif
	      /* Prepare for the next psymtab. */
	      global_syms = objfile->global_psymbols.next;
	      static_syms = objfile->static_psymbols.next;
	      free (class_entered);

	      curr_fd++;
	    }			/* Psymtab for file */
	  else
	    {
	      /* We have a module for which we create a psymtab */

	      mod_name_string = &vt_bits[(long) qMD[curr_md].sbMod];

	      /* We will include the code ranges of any files that happen to
	         overlap with this module */

	      /* So, first pick the lower of the file's and module's start addresses */
	      start_adr = CURR_MODULE_START;
	      if (VALID_CURR_FILE)
		{
		  if (CURR_FILE_START < CURR_MODULE_START)
		    {
		      TELL_OBJFILE;
		      warning ("File \"%s\" [0x%x] crosses beginning of module \"%s\".",
			       &vt_bits[(long) qFD[curr_fd].sbFile],
			       curr_fd, mod_name_string);

		      start_adr = CURR_FILE_START;
		    }
		}

	      /* Also pick the lower of the file's and the module's start symbol indices */
	      start_sym = CURR_MODULE_ISYM;
	      if (VALID_CURR_FILE && (CURR_FILE_ISYM < CURR_MODULE_ISYM))
		start_sym = CURR_FILE_ISYM;

	      /* For the end address, we scan through the files till we find one
	         that overlaps the current module but ends beyond it; if no such file exists we
	         simply use the module's start address.  
	         (Note, if file entries themselves overlap
	         we take the longest overlapping extension beyond the end of the module...)
	         We assume that modules never overlap. */

	      end_adr = CURR_MODULE_END;

	      if (VALID_CURR_FILE)
		{
		  while (VALID_CURR_FILE && (CURR_FILE_START < end_adr))
		    {

#ifdef DUMPING
		      if (dumping)
			printf ("Maybe skipping file %s which overlaps with module %s\n",
				&vt_bits[(long) qFD[curr_fd].sbFile], mod_name_string);
#endif
		      if (CURR_FILE_END > end_adr)
			{
			  TELL_OBJFILE;
			  warning ("File \"%s\" [0x%x] crosses end of module \"%s\".",
				   &vt_bits[(long) qFD[curr_fd].sbFile],
				   curr_fd, mod_name_string);
			  end_adr = CURR_FILE_END;
			}
		      curr_fd++;
		    }
		  curr_fd--;	/* back up after going too far */
		}

	      /* Sometimes (compiler bug -- COBOL) the module end address is higher
	         than the start address of the next module, so check for that and
	         adjust accordingly */

	      if (VALID_MODULE (curr_md + 1) && (MODULE_START (curr_md + 1) <= end_adr))
		{
		  TELL_OBJFILE;
		  warning ("Module \"%s\" [0x%x] has ending address after starting address of next module; adjusting ending address down.",
			   mod_name_string, curr_md);
		  end_adr = MODULE_START (curr_md + 1) - 1;	/* Is -4 (or -8 for 64-bit) better? */
		}
	      if (VALID_FILE (curr_fd + 1) && (FILE_START (curr_fd + 1) <= end_adr))
		{
		  TELL_OBJFILE;
		  warning ("Module \"%s\" [0x%x] has ending address after starting address of next file; adjusting ending address down.",
			   mod_name_string, curr_md);
		  end_adr = FILE_START (curr_fd + 1) - 1;	/* Is -4 (or -8 for 64-bit) better? */
		}

	      /* Use one file to get the full name for the module.  This
	         situation can arise if there is executable code in a #include
	         file.  Each file with code in it gets a qFD.  Files which don't
	         contribute code don't get a qFD, even if they include files
	         which do, e.g.: 

	         body.c:                    rtn.h:
	         int x;                     int main() {
	         #include "rtn.h"               return x;
	         }

	         There will a qFD for "rtn.h",and a qMD for "body.c",
	         but no qMD for "rtn.h" or qFD for "body.c"!

	         We pick the name of the last file to overlap with this
	         module.  C convention is to put include files first.  In a
	         perfect world, we could check names and use the file whose full
	         path name ends with the module name. */

	      if (VALID_CURR_FILE)
		full_name_string = &vt_bits[(long) qFD[curr_fd].sbFile];
	      else
		full_name_string = mod_name_string;

	      /* Check if there are any procedures not handled until now, that
	         begin before the start address we have now, and if so, adjust
	         this psymtab's start address to include them.  This handles routines that
	         are in between file or module ranges for some reason (probably
	         indicates a compiler bug */

	      if (CURR_PROC_START < start_adr)
		{
		  TELL_OBJFILE;
		  warning ("Found procedure \"%s\" [0x%x] that is not in any file or module.",
			   &vt_bits[(long) qPD[curr_pd].sbProc], curr_pd);
		  start_adr = CURR_PROC_START;
		  if (CURR_PROC_ISYM < start_sym)
		    start_sym = CURR_PROC_ISYM;
		}

#ifdef DUMPING
	      if (dumping)
		{
		  printf ("Make new psymtab for module %s (%x to %x), using file %s\n",
		     mod_name_string, start_adr, end_adr, full_name_string);
		}
#endif
	      /* Create the basic psymtab, connecting it in the list
	         for this objfile and pointing its symbol entries
	         to the current end of the symbol areas in the objfile.

	         The "ldsymoff" parameter is the byte offset in the LNTT
	         of the first symbol in this file.  Some day we should
	         turn this into an index (fix in hp-symtab-read.c as well).
	         And it's not even the right byte offset, as we're using
	         the size of a union! FIXME!  */
	      pst = hpread_start_psymtab (objfile,
					  full_name_string,
					  start_adr,	/* Low text address */
			      (start_sym * sizeof (struct dntt_type_block)),
	      /* ldsymoff */
					  global_syms,
					  static_syms);

	      /* Set up to only enter each class referenced in this module once.  */
	      class_entered = malloc (B_BYTES (pxdb_header_p->cd_entries));
	      B_CLRALL (class_entered, pxdb_header_p->cd_entries);

	      /* Scan the procedure descriptors for procedures in the current
	         module, based on the starting addresses. */

	      syms_in_pst = scan_procs (&curr_pd, qPD, pxdb_header_p->pd_entries,
					start_adr, end_adr, pst, vt_bits, objfile);

	      /* Get ending symbol offset */

	      end_sym = 0;
	      /* First check for starting index before previous psymtab */
	      if (pst_syms_count && start_sym < pst_syms_array[pst_syms_count - 1].end)
		{
		  end_sym = find_next_pst_start (start_sym);
		}
	      /* Look for next start index of a file or module, or procedure */
	      if (!end_sym)
		{
		  int next_file_isym = find_next_file_isym (start_sym, qFD, curr_fd + 1, pxdb_header_p);
		  int next_module_isym = find_next_module_isym (start_sym, qMD, curr_md + 1, pxdb_header_p);
		  int next_proc_isym = find_next_proc_isym (start_sym, qPD, curr_pd, pxdb_header_p);

		  if (next_file_isym && next_module_isym)
		    {
		      /* pick lower of next file or module start index */
		      end_sym = min (next_file_isym, next_module_isym);
		    }
		  else
		    {
		      /* one of them is zero, pick the other */
		      end_sym = max (next_file_isym, next_module_isym);
		    }

		  /* As a precaution, check next procedure index too */
		  if (!end_sym)
		    end_sym = next_proc_isym;
		  else
		    end_sym = min (end_sym, next_proc_isym);
		}

	      /* Couldn't find procedure, file, or module, use globals as default */
	      if (!end_sym)
		end_sym = pxdb_header_p->globals;

#ifdef DUMPING
	      if (dumping)
		{
		  printf ("Module psymtab indices: %x to %x\n", start_sym, end_sym);
		}
#endif

	      pst = hpread_end_psymtab (pst,
					NULL,	/* psymtab_include_list */
					0,	/* includes_used        */
				  end_sym * sizeof (struct dntt_type_block),
	      /* byte index in LNTT of end 
	         = capping symbol offset   
	         = LDSYMOFF of nextfile */
					end_adr,	/* text high */
					NULL,	/* dependency_list      */
					0);	/* dependencies_used    */

	      record_pst_syms (start_sym, end_sym);

	      if (NULL == pst)
		warning ("No symbols in psymtab for module \"%s\" [0x%x].", mod_name_string, curr_md);

#ifdef DUMPING
	      if (dumping)
		{
		  printf ("Made new psymtab for module %s (%x to %x), sym %x to %x.\n",
			  mod_name_string, start_adr, end_adr, CURR_MODULE_ISYM, end_sym);
		}
#endif

	      /* Prepare for the next psymtab. */
	      global_syms = objfile->global_psymbols.next;
	      static_syms = objfile->static_psymbols.next;
	      free (class_entered);

	      curr_md++;
	      curr_fd++;
	    }			/* psymtab for module */
	}			/* psymtab for non-bogus file or module */
    }				/* End of while loop over all files & modules */

  /* There may be some routines after all files and modules -- these will get
     inserted in a separate new module of their own */
  if (VALID_CURR_PROC)
    {
      start_adr = CURR_PROC_START;
      end_adr = qPD[pxdb_header_p->pd_entries - 1].adrEnd;
      TELL_OBJFILE;
      warning ("Found functions beyond end of all files and modules [0x%x].", curr_pd);
#ifdef DUMPING
      if (dumping)
	{
	  printf ("Orphan functions at end, PD %d and beyond (%x to %x)\n",
		  curr_pd, start_adr, end_adr);
	}
#endif
      pst = hpread_start_psymtab (objfile,
				  "orphans",
				  start_adr,	/* Low text address */
			 (CURR_PROC_ISYM * sizeof (struct dntt_type_block)),
      /* ldsymoff */
				  global_syms,
				  static_syms);

      scan_procs (&curr_pd, qPD, pxdb_header_p->pd_entries,
		  start_adr, end_adr, pst, vt_bits, objfile);

      pst = hpread_end_psymtab (pst,
				NULL,	/* psymtab_include_list */
				0,	/* includes_used */
		   pxdb_header_p->globals * sizeof (struct dntt_type_block),
      /* byte index in LNTT of end 
         = capping symbol offset   
         = LDSYMOFF of nextfile */
				end_adr,	/* text high  */
				NULL,	/* dependency_list */
				0);	/* dependencies_used */
    }


#ifdef NEVER_NEVER
  /* Now build psts for non-module things (in the tail of
     the LNTT, after the last END MODULE entry).

     If null psts were kept on the chain, this would be
     a solution.  FIXME */
  pst = hpread_start_psymtab (objfile,
			      "globals",
			      0,
			      (pxdb_header_p->globals
			       * sizeof (struct dntt_type_block)),
			      objfile->global_psymbols.next,
			      objfile->static_psymbols.next);
  hpread_end_psymtab (pst,
		      NULL, 0,
		      (max_LNTT_sym_index * sizeof (struct dntt_type_block)),
		      0,
		      NULL, 0);
#endif

  clear_pst_syms ();

  return 1;

}				/* End of hpread_quick_traverse. */


/* Get appropriate header, based on pxdb type. 
   Return value: 1 if ok, 0 if not */
int
hpread_get_header (struct objfile *objfile, PXDB_header_ptr pxdb_header_p)
{
  asection *pinfo_section, *debug_section, *header_section;

#ifdef DUMPING
  /* Turn on for debugging information */
  static int dumping = 0;
#endif

  header_section = bfd_get_section_by_name (objfile->obfd, "$HEADER$");
  if (!header_section)
    {
      /* We don't have either PINFO or DEBUG sections.  But
         stuff like "libc.sl" has no debug info.  There's no
         need to warn the user of this, as it may be ok. The
         caller will figure it out and issue any needed
         messages. */
#ifdef DUMPING
      if (dumping)
	printf ("==No debug info at all for %s.\n", objfile->name);
#endif

      return 0;
    }

  /* We would like either a $DEBUG$ or $PINFO$ section.
     Once we know which, we can understand the header
     data (which we have defined to suit the more common
     $DEBUG$ case). */
  debug_section = bfd_get_section_by_name (objfile->obfd, "$DEBUG$");
  pinfo_section = bfd_get_section_by_name (objfile->obfd, "$PINFO$");
  if (debug_section)
    {
      /* The expected case: normal pxdb header. */
      bfd_get_section_contents (objfile->obfd, header_section,
				pxdb_header_p, 0, sizeof (PXDB_header));

      if (!pxdb_header_p->pxdbed)
	{
	  /* This shouldn't happen if we check in "symfile.c". */
	  return 0;
	}			/* DEBUG section */
    }

  else if (pinfo_section)
    {
      /* The DOC case; we need to translate this into a
         regular header. */
      DOC_info_PXDB_header doc_header;

#ifdef DUMPING
      if (dumping)
	{
	  printf ("==OOps, PINFO, let's try to handle this, %s.\n", objfile->name);
	}
#endif

      bfd_get_section_contents (objfile->obfd,
				header_section,
				&doc_header, 0,
				sizeof (DOC_info_PXDB_header));

      if (!doc_header.pxdbed)
	{
	  /* This shouldn't happen if we check in "symfile.c". */
	  warning ("File \"%s\" not processed by pxdb!", objfile->name);
	  return 0;
	}

      /* Copy relevent fields to standard header passed in. */
      pxdb_header_p->pd_entries = doc_header.pd_entries;
      pxdb_header_p->fd_entries = doc_header.fd_entries;
      pxdb_header_p->md_entries = doc_header.md_entries;
      pxdb_header_p->pxdbed = doc_header.pxdbed;
      pxdb_header_p->bighdr = doc_header.bighdr;
      pxdb_header_p->sa_header = doc_header.sa_header;
      pxdb_header_p->inlined = doc_header.inlined;
      pxdb_header_p->globals = doc_header.globals;
      pxdb_header_p->time = doc_header.time;
      pxdb_header_p->pg_entries = doc_header.pg_entries;
      pxdb_header_p->functions = doc_header.functions;
      pxdb_header_p->files = doc_header.files;
      pxdb_header_p->cd_entries = doc_header.cd_entries;
      pxdb_header_p->aa_entries = doc_header.aa_entries;
      pxdb_header_p->oi_entries = doc_header.oi_entries;
      pxdb_header_p->version = doc_header.version;
    }				/* PINFO section */

  else
    {
#ifdef DUMPING
      if (dumping)
	printf ("==No debug info at all for %s.\n", objfile->name);
#endif

      return 0;

    }

  return 1;
}				/* End of hpread_get_header */
#endif /* QUICK_LOOK_UP */


/* Initialization for reading native HP C debug symbols from OBJFILE.

   Its only purpose in life is to set up the symbol reader's private
   per-objfile data structures, and read in the raw contents of the debug
   sections (attaching pointers to the debug info into the private data
   structures).

   Since BFD doesn't know how to read debug symbols in a format-independent
   way (and may never do so...), we have to do it ourselves.  Note we may
   be called on a file without native HP C debugging symbols.

   FIXME, there should be a cleaner peephole into the BFD environment
   here. */
void
hpread_symfile_init (struct objfile *objfile)
{
  asection *vt_section, *slt_section, *lntt_section, *gntt_section;

  /* Allocate struct to keep track of the symfile */
  objfile->sym_private = (PTR)
    xmmalloc (objfile->md, sizeof (struct hpread_symfile_info));
  memset (objfile->sym_private, 0, sizeof (struct hpread_symfile_info));

  /* We haven't read in any types yet.  */
  TYPE_VECTOR (objfile) = 0;

  /* Read in data from the $GNTT$ subspace.  */
  gntt_section = bfd_get_section_by_name (objfile->obfd, "$GNTT$");
  if (!gntt_section)
    return;

  GNTT (objfile)
    = obstack_alloc (&objfile->symbol_obstack,
		     bfd_section_size (objfile->obfd, gntt_section));

  bfd_get_section_contents (objfile->obfd, gntt_section, GNTT (objfile),
			 0, bfd_section_size (objfile->obfd, gntt_section));

  GNTT_SYMCOUNT (objfile)
    = bfd_section_size (objfile->obfd, gntt_section)
    / sizeof (struct dntt_type_block);

  /* Read in data from the $LNTT$ subspace.   Also keep track of the number
     of LNTT symbols.

     FIXME: this could be moved into the psymtab-to-symtab expansion
     code, and save startup time.  At the moment this data is
     still used, though.  We'd need a way to tell hp-symtab-read.c
     whether or not to load the LNTT. */
  lntt_section = bfd_get_section_by_name (objfile->obfd, "$LNTT$");
  if (!lntt_section)
    return;

  LNTT (objfile)
    = obstack_alloc (&objfile->symbol_obstack,
		     bfd_section_size (objfile->obfd, lntt_section));

  bfd_get_section_contents (objfile->obfd, lntt_section, LNTT (objfile),
			 0, bfd_section_size (objfile->obfd, lntt_section));

  LNTT_SYMCOUNT (objfile)
    = bfd_section_size (objfile->obfd, lntt_section)
    / sizeof (struct dntt_type_block);

  /* Read in data from the $SLT$ subspace.  $SLT$ contains information
     on source line numbers.  */
  slt_section = bfd_get_section_by_name (objfile->obfd, "$SLT$");
  if (!slt_section)
    return;

  SLT (objfile) =
    obstack_alloc (&objfile->symbol_obstack,
		   bfd_section_size (objfile->obfd, slt_section));

  bfd_get_section_contents (objfile->obfd, slt_section, SLT (objfile),
			  0, bfd_section_size (objfile->obfd, slt_section));

  /* Read in data from the $VT$ subspace.  $VT$ contains things like
     names and constants.  Keep track of the number of symbols in the VT.  */
  vt_section = bfd_get_section_by_name (objfile->obfd, "$VT$");
  if (!vt_section)
    return;

  VT_SIZE (objfile) = bfd_section_size (objfile->obfd, vt_section);

  VT (objfile) =
    (char *) obstack_alloc (&objfile->symbol_obstack,
			    VT_SIZE (objfile));

  bfd_get_section_contents (objfile->obfd, vt_section, VT (objfile),
			    0, VT_SIZE (objfile));
}

/* Scan and build partial symbols for a symbol file.

   The minimal symbol table (either SOM or HP a.out) has already been
   read in; all we need to do is setup partial symbols based on the
   native debugging information.

   Note that the minimal table is produced by the linker, and has
   only global routines in it; the psymtab is based on compiler-
   generated debug information and has non-global
   routines in it as well as files and class information.

   We assume hpread_symfile_init has been called to initialize the
   symbol reader's private data structures.

   MAINLINE is true if we are reading the main symbol table (as
   opposed to a shared lib or dynamically loaded file). */

void
hpread_build_psymtabs (struct objfile *objfile, int mainline)
{

#ifdef DUMPING
  /* Turn this on to get debugging output. */
  static int dumping = 0;
#endif

  char *namestring;
  int past_first_source_file = 0;
  struct cleanup *old_chain;

  int hp_symnum, symcount, i;
  int scan_start = 0;

  union dnttentry *dn_bufp;
  unsigned long valu;
  char *p;
  int texthigh = 0;
  int have_name = 0;

  /* Current partial symtab */
  struct partial_symtab *pst;

  /* List of current psymtab's include files */
  char **psymtab_include_list;
  int includes_allocated;
  int includes_used;

  /* Index within current psymtab dependency list */
  struct partial_symtab **dependency_list;
  int dependencies_used, dependencies_allocated;

  /* Just in case the stabs reader left turds lying around.  */
  free_pending_blocks ();
  make_cleanup (really_free_pendings, 0);

  pst = (struct partial_symtab *) 0;

  /* We shouldn't use alloca, instead use malloc/free.  Doing so avoids
     a number of problems with cross compilation and creating useless holes
     in the stack when we have to allocate new entries.  FIXME.  */

  includes_allocated = 30;
  includes_used = 0;
  psymtab_include_list = (char **) alloca (includes_allocated *
					   sizeof (char *));

  dependencies_allocated = 30;
  dependencies_used = 0;
  dependency_list =
    (struct partial_symtab **) alloca (dependencies_allocated *
				       sizeof (struct partial_symtab *));

  old_chain = make_cleanup_free_objfile (objfile);

  last_source_file = 0;

#ifdef QUICK_LOOK_UP
  {
    /* Begin code for new-style loading of quick look-up tables. */

    /* elz: this checks whether the file has beeen processed by pxdb.
       If not we would like to try to read the psymbols in
       anyway, but it turns out to be not so easy. So this could 
       actually be commented out, but I leave it in, just in case
       we decide to add support for non-pxdb-ed stuff in the future. */
    PXDB_header pxdb_header;
    int found_modules_in_program;

    if (hpread_get_header (objfile, &pxdb_header))
      {
	/* Build a minimal table.  No types, no global variables,
	   no include files.... */
#ifdef DUMPING
	if (dumping)
	  printf ("\nNew method for %s\n", objfile->name);
#endif

	/* elz: quick_traverse returns true if it found
	   some modules in the main source file, other
	   than those in end.c
	   In C and C++, all the files have MODULES entries
	   in the LNTT, and the quick table traverse is all 
	   based on finding these MODULES entries. Without 
	   those it cannot work. 
	   It happens that F77 programs don't have MODULES
	   so the quick traverse gets confused. F90 programs
	   have modules, and the quick method still works.
	   So, if modules (other than those in end.c) are
	   not found we give up on the quick table stuff, 
	   and fall back on the slower method  */
	found_modules_in_program = hpread_quick_traverse (objfile,
							  GNTT (objfile),
							  VT (objfile),
							  &pxdb_header);

	discard_cleanups (old_chain);

	/* Set up to scan the global section of the LNTT.

	   This field is not always correct: if there are
	   no globals, it will point to the last record in
	   the regular LNTT, which is usually an END MODULE.

	   Since it might happen that there could be a file
	   with just one global record, there's no way to
	   tell other than by looking at the record, so that's
	   done below. */
	if (found_modules_in_program)
	  scan_start = pxdb_header.globals;
      }
#ifdef DUMPING
    else
      {
	if (dumping)
	  printf ("\nGoing on to old method for %s\n", objfile->name);
      }
#endif
  }
#endif /* QUICK_LOOK_UP */

  /* Make two passes, one over the GNTT symbols, the other for the
     LNTT symbols.

     JB comment: above isn't true--they only make one pass, over
     the LNTT.  */
  for (i = 0; i < 1; i++)
    {
      int within_function = 0;

      if (i)
	symcount = GNTT_SYMCOUNT (objfile);
      else
	symcount = LNTT_SYMCOUNT (objfile);


      for (hp_symnum = scan_start; hp_symnum < symcount; hp_symnum++)
	{
	  QUIT;
	  if (i)
	    dn_bufp = hpread_get_gntt (hp_symnum, objfile);
	  else
	    dn_bufp = hpread_get_lntt (hp_symnum, objfile);

	  if (dn_bufp->dblock.extension)
	    continue;

	  /* Only handle things which are necessary for minimal symbols.
	     everything else is ignored.  */
	  switch (dn_bufp->dblock.kind)
	    {
	    case DNTT_TYPE_SRCFILE:
	      {
#ifdef QUICK_LOOK_UP
		if (scan_start == hp_symnum
		    && symcount == hp_symnum + 1)
		  {
		    /* If there are NO globals in an executable,
		       PXDB's index to the globals will point to
		       the last record in the file, which 
		       could be this record. (this happened for F77 libraries)
		       ignore it and be done! */
		    continue;
		  }
#endif /* QUICK_LOOK_UP */

		/* A source file of some kind.  Note this may simply
		   be an included file.  */
		SET_NAMESTRING (dn_bufp, &namestring, objfile);

		/* Check if this is the source file we are already working
		   with.  */
		if (pst && !strcmp (namestring, pst->filename))
		  continue;

		/* Check if this is an include file, if so check if we have
		   already seen it.  Add it to the include list */
		p = strrchr (namestring, '.');
		if (!strcmp (p, ".h"))
		  {
		    int j, found;

		    found = 0;
		    for (j = 0; j < includes_used; j++)
		      if (!strcmp (namestring, psymtab_include_list[j]))
			{
			  found = 1;
			  break;
			}
		    if (found)
		      continue;

		    /* Add it to the list of includes seen so far and
		       allocate more include space if necessary.  */
		    psymtab_include_list[includes_used++] = namestring;
		    if (includes_used >= includes_allocated)
		      {
			char **orig = psymtab_include_list;

			psymtab_include_list = (char **)
			  alloca ((includes_allocated *= 2) *
				  sizeof (char *));
			memcpy ((PTR) psymtab_include_list, (PTR) orig,
				includes_used * sizeof (char *));
		      }
		    continue;
		  }

		if (pst)
		  {
		    if (!have_name)
		      {
			pst->filename = (char *)
			  obstack_alloc (&pst->objfile->psymbol_obstack,
					 strlen (namestring) + 1);
			strcpy (pst->filename, namestring);
			have_name = 1;
			continue;
		      }
		    continue;
		  }

		/* This is a bonafide new source file.
		   End the current partial symtab and start a new one.  */

		if (pst && past_first_source_file)
		  {
		    hpread_end_psymtab (pst, psymtab_include_list,
					includes_used,
					(hp_symnum
					 * sizeof (struct dntt_type_block)),
					texthigh,
					dependency_list, dependencies_used);
		    pst = (struct partial_symtab *) 0;
		    includes_used = 0;
		    dependencies_used = 0;
		  }
		else
		  past_first_source_file = 1;

		valu = hpread_get_textlow (i, hp_symnum, objfile, symcount);
		valu += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
		pst = hpread_start_psymtab (objfile,
					    namestring, valu,
					    (hp_symnum
					 * sizeof (struct dntt_type_block)),
					    objfile->global_psymbols.next,
					    objfile->static_psymbols.next);
		texthigh = valu;
		have_name = 1;
		continue;
	      }

	    case DNTT_TYPE_MODULE:
	      /* A source file.  It's still unclear to me what the
	         real difference between a DNTT_TYPE_SRCFILE and DNTT_TYPE_MODULE
	         is supposed to be.  */

	      /* First end the previous psymtab */
	      if (pst)
		{
		  hpread_end_psymtab (pst, psymtab_include_list, includes_used,
				      ((hp_symnum - 1)
				       * sizeof (struct dntt_type_block)),
				      texthigh,
				      dependency_list, dependencies_used);
		  pst = (struct partial_symtab *) 0;
		  includes_used = 0;
		  dependencies_used = 0;
		  have_name = 0;
		}

	      /* Now begin a new module and a new psymtab for it */
	      SET_NAMESTRING (dn_bufp, &namestring, objfile);
	      valu = hpread_get_textlow (i, hp_symnum, objfile, symcount);
	      valu += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
	      if (!pst)
		{
		  pst = hpread_start_psymtab (objfile,
					      namestring, valu,
					      (hp_symnum
					 * sizeof (struct dntt_type_block)),
					      objfile->global_psymbols.next,
					      objfile->static_psymbols.next);
		  texthigh = valu;
		  have_name = 0;
		}
	      continue;

	    case DNTT_TYPE_FUNCTION:
	    case DNTT_TYPE_ENTRY:
	      /* The beginning of a function.  DNTT_TYPE_ENTRY may also denote
	         a secondary entry point.  */
	      valu = dn_bufp->dfunc.hiaddr + ANOFFSET (objfile->section_offsets,
						       SECT_OFF_TEXT (objfile));
	      if (valu > texthigh)
		texthigh = valu;
	      valu = dn_bufp->dfunc.lowaddr +
		ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
	      SET_NAMESTRING (dn_bufp, &namestring, objfile);
	      if (dn_bufp->dfunc.global)
		add_psymbol_to_list (namestring, strlen (namestring),
				     VAR_NAMESPACE, LOC_BLOCK,
				     &objfile->global_psymbols, valu,
				     0, language_unknown, objfile);
	      else
		add_psymbol_to_list (namestring, strlen (namestring),
				     VAR_NAMESPACE, LOC_BLOCK,
				     &objfile->static_psymbols, valu,
				     0, language_unknown, objfile);
	      within_function = 1;
	      continue;

	    case DNTT_TYPE_DOC_FUNCTION:
	      valu = dn_bufp->ddocfunc.hiaddr + ANOFFSET (objfile->section_offsets,
							  SECT_OFF_TEXT (objfile));
	      if (valu > texthigh)
		texthigh = valu;
	      valu = dn_bufp->ddocfunc.lowaddr +
		ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
	      SET_NAMESTRING (dn_bufp, &namestring, objfile);
	      if (dn_bufp->ddocfunc.global)
		add_psymbol_to_list (namestring, strlen (namestring),
				     VAR_NAMESPACE, LOC_BLOCK,
				     &objfile->global_psymbols, valu,
				     0, language_unknown, objfile);
	      else
		add_psymbol_to_list (namestring, strlen (namestring),
				     VAR_NAMESPACE, LOC_BLOCK,
				     &objfile->static_psymbols, valu,
				     0, language_unknown, objfile);
	      within_function = 1;
	      continue;

	    case DNTT_TYPE_BEGIN:
	    case DNTT_TYPE_END:
	      /* We don't check MODULE end here, because there can be
	         symbols beyond the module end which properly belong to the
	         current psymtab -- so we wait till the next MODULE start */


#ifdef QUICK_LOOK_UP
	      if (scan_start == hp_symnum
		  && symcount == hp_symnum + 1)
		{
		  /* If there are NO globals in an executable,
		     PXDB's index to the globals will point to
		     the last record in the file, which is
		     probably an END MODULE, i.e. this record.
		     ignore it and be done! */
		  continue;
		}
#endif /* QUICK_LOOK_UP */

	      /* Scope block begin/end.  We only care about function
	         and file blocks right now.  */

	      if ((dn_bufp->dend.endkind == DNTT_TYPE_FUNCTION) ||
		  (dn_bufp->dend.endkind == DNTT_TYPE_DOC_FUNCTION))
		within_function = 0;
	      continue;

	    case DNTT_TYPE_SVAR:
	    case DNTT_TYPE_DVAR:
	    case DNTT_TYPE_TYPEDEF:
	    case DNTT_TYPE_TAGDEF:
	      {
		/* Variables, typedefs an the like.  */
		enum address_class storage;
		namespace_enum namespace;

		/* Don't add locals to the partial symbol table.  */
		if (within_function
		    && (dn_bufp->dblock.kind == DNTT_TYPE_SVAR
			|| dn_bufp->dblock.kind == DNTT_TYPE_DVAR))
		  continue;

		/* TAGDEFs go into the structure namespace.  */
		if (dn_bufp->dblock.kind == DNTT_TYPE_TAGDEF)
		  namespace = STRUCT_NAMESPACE;
		else
		  namespace = VAR_NAMESPACE;

		/* What kind of "storage" does this use?  */
		if (dn_bufp->dblock.kind == DNTT_TYPE_SVAR)
		  storage = LOC_STATIC;
		else if (dn_bufp->dblock.kind == DNTT_TYPE_DVAR
			 && dn_bufp->ddvar.regvar)
		  storage = LOC_REGISTER;
		else if (dn_bufp->dblock.kind == DNTT_TYPE_DVAR)
		  storage = LOC_LOCAL;
		else
		  storage = LOC_UNDEF;

		SET_NAMESTRING (dn_bufp, &namestring, objfile);
		if (!pst)
		  {
		    pst = hpread_start_psymtab (objfile,
						"globals", 0,
						(hp_symnum
					 * sizeof (struct dntt_type_block)),
					      objfile->global_psymbols.next,
					     objfile->static_psymbols.next);
		  }

		/* Compute address of the data symbol */
		valu = dn_bufp->dsvar.location;
		/* Relocate in case it's in a shared library */
		if (storage == LOC_STATIC)
		  valu += ANOFFSET (objfile->section_offsets, SECT_OFF_DATA (objfile));

		/* Luckily, dvar, svar, typedef, and tagdef all
		   have their "global" bit in the same place, so it works
		   (though it's bad programming practice) to reference
		   "dsvar.global" even though we may be looking at
		   any of the above four types. */
		if (dn_bufp->dsvar.global)
		  {
		    add_psymbol_to_list (namestring, strlen (namestring),
					 namespace, storage,
					 &objfile->global_psymbols,
					 valu,
					 0, language_unknown, objfile);
		  }
		else
		  {
		    add_psymbol_to_list (namestring, strlen (namestring),
					 namespace, storage,
					 &objfile->static_psymbols,
					 valu,
					 0, language_unknown, objfile);
		  }

		/* For TAGDEF's, the above code added the tagname to the
		   struct namespace. This will cause tag "t" to be found
		   on a reference of the form "(struct t) x". But for
		   C++ classes, "t" will also be a typename, which we
		   want to find on a reference of the form "ptype t".
		   Therefore, we also add "t" to the var namespace.
		   Do the same for enum's due to the way aCC generates
		   debug info for these (see more extended comment
		   in hp-symtab-read.c).
		   We do the same for templates, so that "ptype t"
		   where "t" is a template also works. */
		if (dn_bufp->dblock.kind == DNTT_TYPE_TAGDEF &&
		  dn_bufp->dtype.type.dnttp.index < LNTT_SYMCOUNT (objfile))
		  {
		    int global = dn_bufp->dtag.global;
		    /* Look ahead to see if it's a C++ class */
		    dn_bufp = hpread_get_lntt (dn_bufp->dtype.type.dnttp.index, objfile);
		    if (dn_bufp->dblock.kind == DNTT_TYPE_CLASS ||
			dn_bufp->dblock.kind == DNTT_TYPE_ENUM ||
			dn_bufp->dblock.kind == DNTT_TYPE_TEMPLATE)
		      {
			if (global)
			  {
			    add_psymbol_to_list (namestring, strlen (namestring),
						 VAR_NAMESPACE, storage,
						 &objfile->global_psymbols,
						 dn_bufp->dsvar.location,
					      0, language_unknown, objfile);
			  }
			else
			  {
			    add_psymbol_to_list (namestring, strlen (namestring),
						 VAR_NAMESPACE, storage,
						 &objfile->static_psymbols,
						 dn_bufp->dsvar.location,
					      0, language_unknown, objfile);
			  }
		      }
		  }
	      }
	      continue;

	    case DNTT_TYPE_MEMENUM:
	    case DNTT_TYPE_CONST:
	      /* Constants and members of enumerated types.  */
	      SET_NAMESTRING (dn_bufp, &namestring, objfile);
	      if (!pst)
		{
		  pst = hpread_start_psymtab (objfile,
					      "globals", 0,
					      (hp_symnum
					 * sizeof (struct dntt_type_block)),
					      objfile->global_psymbols.next,
					      objfile->static_psymbols.next);
		}
	      if (dn_bufp->dconst.global)
		add_psymbol_to_list (namestring, strlen (namestring),
				     VAR_NAMESPACE, LOC_CONST,
				     &objfile->global_psymbols, 0,
				     0, language_unknown, objfile);
	      else
		add_psymbol_to_list (namestring, strlen (namestring),
				     VAR_NAMESPACE, LOC_CONST,
				     &objfile->static_psymbols, 0,
				     0, language_unknown, objfile);
	      continue;
	    default:
	      continue;
	    }
	}
    }

  /* End any pending partial symbol table. */
  if (pst)
    {
      hpread_end_psymtab (pst, psymtab_include_list, includes_used,
			  hp_symnum * sizeof (struct dntt_type_block),
			  0, dependency_list, dependencies_used);
    }

  discard_cleanups (old_chain);
}

/* Perform any local cleanups required when we are done with a particular
   objfile.  I.E, we are in the process of discarding all symbol information
   for an objfile, freeing up all memory held for it, and unlinking the
   objfile struct from the global list of known objfiles. */

void
hpread_symfile_finish (struct objfile *objfile)
{
  if (objfile->sym_private != NULL)
    {
      mfree (objfile->md, objfile->sym_private);
    }
}


/* The remaining functions are all for internal use only.  */

/* Various small functions to get entries in the debug symbol sections.  */

union dnttentry *
hpread_get_lntt (int index, struct objfile *objfile)
{
  return (union dnttentry *)
    &(LNTT (objfile)[(index * sizeof (struct dntt_type_block))]);
}

static union dnttentry *
hpread_get_gntt (int index, struct objfile *objfile)
{
  return (union dnttentry *)
    &(GNTT (objfile)[(index * sizeof (struct dntt_type_block))]);
}

union sltentry *
hpread_get_slt (int index, struct objfile *objfile)
{
  return (union sltentry *) &(SLT (objfile)[index * sizeof (union sltentry)]);
}

/* Get the low address associated with some symbol (typically the start
   of a particular source file or module).  Since that information is not
   stored as part of the DNTT_TYPE_MODULE or DNTT_TYPE_SRCFILE symbol we
   must infer it from the existence of DNTT_TYPE_FUNCTION symbols.  */

static unsigned long
hpread_get_textlow (int global, int index, struct objfile *objfile,
		    int symcount)
{
  union dnttentry *dn_bufp;
  struct minimal_symbol *msymbol;

  /* Look for a DNTT_TYPE_FUNCTION symbol.  */
  if (index < symcount)		/* symcount is the number of symbols in */
    {				/*   the dbinfo, LNTT table */
      do
	{
	  if (global)
	    dn_bufp = hpread_get_gntt (index++, objfile);
	  else
	    dn_bufp = hpread_get_lntt (index++, objfile);
	}
      while (dn_bufp->dblock.kind != DNTT_TYPE_FUNCTION
	     && dn_bufp->dblock.kind != DNTT_TYPE_DOC_FUNCTION
	     && dn_bufp->dblock.kind != DNTT_TYPE_END
	     && index < symcount);
    }

  /* Avoid going past a DNTT_TYPE_END when looking for a DNTT_TYPE_FUNCTION.  This
     might happen when a sourcefile has no functions.  */
  if (dn_bufp->dblock.kind == DNTT_TYPE_END)
    return 0;

  /* Avoid going past the end of the LNTT file */
  if (index == symcount)
    return 0;

  /* The minimal symbols are typically more accurate for some reason.  */
  if (dn_bufp->dblock.kind == DNTT_TYPE_FUNCTION)
    msymbol = lookup_minimal_symbol (dn_bufp->dfunc.name + VT (objfile), NULL,
				     objfile);
  else				/* must be a DNTT_TYPE_DOC_FUNCTION */
    msymbol = lookup_minimal_symbol (dn_bufp->ddocfunc.name + VT (objfile), NULL,
				     objfile);

  if (msymbol)
    return SYMBOL_VALUE_ADDRESS (msymbol);
  else
    return dn_bufp->dfunc.lowaddr;
}

/* Allocate and partially fill a partial symtab.  It will be
   completely filled at the end of the symbol list.

   SYMFILE_NAME is the name of the symbol-file we are reading from, and ADDR
   is the address relative to which its symbols are (incremental) or 0
   (normal). */

static struct partial_symtab *
hpread_start_psymtab (struct objfile *objfile, char *filename,
		      CORE_ADDR textlow, int ldsymoff,
		      struct partial_symbol **global_syms,
		      struct partial_symbol **static_syms)
{
  int offset = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
  extern void hpread_psymtab_to_symtab ();
  struct partial_symtab *result =
  start_psymtab_common (objfile, objfile->section_offsets,
			filename, textlow, global_syms, static_syms);

  result->textlow += offset;
  result->read_symtab_private = (char *)
    obstack_alloc (&objfile->psymbol_obstack, sizeof (struct symloc));
  LDSYMOFF (result) = ldsymoff;
  result->read_symtab = hpread_psymtab_to_symtab;

  return result;
}


/* Close off the current usage of PST.  
   Returns PST or NULL if the partial symtab was empty and thrown away.

   capping_symbol_offset  --Byte index in LNTT or GNTT of the
   last symbol processed during the build
   of the previous pst.

   FIXME:  List variables and peculiarities of same.  */

static struct partial_symtab *
hpread_end_psymtab (struct partial_symtab *pst, char **include_list,
		    int num_includes, int capping_symbol_offset,
		    CORE_ADDR capping_text,
		    struct partial_symtab **dependency_list,
		    int number_dependencies)
{
  int i;
  struct objfile *objfile = pst->objfile;
  int offset = ANOFFSET (pst->section_offsets, SECT_OFF_TEXT (objfile));

#ifdef DUMPING
  /* Turn on to see what kind of a psymtab we've built. */
  static int dumping = 0;
#endif

  if (capping_symbol_offset != -1)
    LDSYMLEN (pst) = capping_symbol_offset - LDSYMOFF (pst);
  else
    LDSYMLEN (pst) = 0;
  pst->texthigh = capping_text + offset;

  pst->n_global_syms =
    objfile->global_psymbols.next - (objfile->global_psymbols.list + pst->globals_offset);
  pst->n_static_syms =
    objfile->static_psymbols.next - (objfile->static_psymbols.list + pst->statics_offset);

#ifdef DUMPING
  if (dumping)
    {
      printf ("\nPst %s, LDSYMOFF %x (%x), LDSYMLEN %x (%x), globals %d, statics %d\n",
	      pst->filename,
	      LDSYMOFF (pst),
	      LDSYMOFF (pst) / sizeof (struct dntt_type_block),
	      LDSYMLEN (pst),
	      LDSYMLEN (pst) / sizeof (struct dntt_type_block),
	      pst->n_global_syms, pst->n_static_syms);
    }
#endif

  pst->number_of_dependencies = number_dependencies;
  if (number_dependencies)
    {
      pst->dependencies = (struct partial_symtab **)
	obstack_alloc (&objfile->psymbol_obstack,
		    number_dependencies * sizeof (struct partial_symtab *));
      memcpy (pst->dependencies, dependency_list,
	      number_dependencies * sizeof (struct partial_symtab *));
    }
  else
    pst->dependencies = 0;

  for (i = 0; i < num_includes; i++)
    {
      struct partial_symtab *subpst =
      allocate_psymtab (include_list[i], objfile);

      subpst->section_offsets = pst->section_offsets;
      subpst->read_symtab_private =
	(char *) obstack_alloc (&objfile->psymbol_obstack,
				sizeof (struct symloc));
      LDSYMOFF (subpst) =
	LDSYMLEN (subpst) =
	subpst->textlow =
	subpst->texthigh = 0;

      /* We could save slight bits of space by only making one of these,
         shared by the entire set of include files.  FIXME-someday.  */
      subpst->dependencies = (struct partial_symtab **)
	obstack_alloc (&objfile->psymbol_obstack,
		       sizeof (struct partial_symtab *));
      subpst->dependencies[0] = pst;
      subpst->number_of_dependencies = 1;

      subpst->globals_offset =
	subpst->n_global_syms =
	subpst->statics_offset =
	subpst->n_static_syms = 0;

      subpst->readin = 0;
      subpst->symtab = 0;
      subpst->read_symtab = pst->read_symtab;
    }

  sort_pst_symbols (pst);

  /* If there is already a psymtab or symtab for a file of this name, remove it.
     (If there is a symtab, more drastic things also happen.)
     This happens in VxWorks.  */
  free_named_symtabs (pst->filename);

  if (num_includes == 0
      && number_dependencies == 0
      && pst->n_global_syms == 0
      && pst->n_static_syms == 0)
    {
      /* Throw away this psymtab, it's empty.  We can't deallocate it, since
         it is on the obstack, but we can forget to chain it on the list. 
         Empty psymtabs happen as a result of header files which don't have
         any symbols in them.  There can be a lot of them.  But this check
         is wrong, in that a psymtab with N_SLINE entries but nothing else
         is not empty, but we don't realize that.  Fixing that without slowing
         things down might be tricky.
         It's also wrong if we're using the quick look-up tables, as
         we can get empty psymtabs from modules with no routines in
         them. */

      discard_psymtab (pst);

      /* Indicate that psymtab was thrown away.  */
      pst = (struct partial_symtab *) NULL;

    }
  return pst;
}


/* End of hp-psymtab-read.c */

/* Set indentation to 4 spaces for Emacs; this file is
   mostly non-GNU-ish in its style :-( */
#if 0
***Local Variables:
***c - basic - offset:4
*** End:
#endif