|  | /* Read a symbol table in ECOFF format (Third-Eye). | 
|  |  | 
|  | Copyright (C) 1986-2022 Free Software Foundation, Inc. | 
|  |  | 
|  | Original version contributed by Alessandro Forin (af@cs.cmu.edu) at | 
|  | CMU.  Major work by Per Bothner, John Gilmore and Ian Lance Taylor | 
|  | at Cygnus Support. | 
|  |  | 
|  | 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 3 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, see <http://www.gnu.org/licenses/>.  */ | 
|  |  | 
|  | /* This module provides the function mdebug_build_psymtabs.  It reads | 
|  | ECOFF debugging information into partial symbol tables.  The | 
|  | debugging information is read from two structures.  A struct | 
|  | ecoff_debug_swap includes the sizes of each ECOFF structure and | 
|  | swapping routines; these are fixed for a particular target.  A | 
|  | struct ecoff_debug_info points to the debugging information for a | 
|  | particular object file. | 
|  |  | 
|  | ECOFF symbol tables are mostly written in the byte order of the | 
|  | target machine.  However, one section of the table (the auxiliary | 
|  | symbol information) is written in the host byte order.  There is a | 
|  | bit in the other symbol info which describes which host byte order | 
|  | was used.  ECOFF thereby takes the trophy from Intel `b.out' for | 
|  | the most brain-dead adaptation of a file format to byte order. | 
|  |  | 
|  | This module can read all four of the known byte-order combinations, | 
|  | on any type of host.  */ | 
|  |  | 
|  | #include "defs.h" | 
|  | #include "symtab.h" | 
|  | #include "gdbtypes.h" | 
|  | #include "gdbcore.h" | 
|  | #include "filenames.h" | 
|  | #include "objfiles.h" | 
|  | #include "gdbsupport/gdb_obstack.h" | 
|  | #include "buildsym-legacy.h" | 
|  | #include "stabsread.h" | 
|  | #include "complaints.h" | 
|  | #include "demangle.h" | 
|  | #include "gdb-demangle.h" | 
|  | #include "block.h" | 
|  | #include "dictionary.h" | 
|  | #include "mdebugread.h" | 
|  | #include <sys/stat.h> | 
|  | #include "psympriv.h" | 
|  | #include "source.h" | 
|  |  | 
|  | #include "bfd.h" | 
|  |  | 
|  | #include "coff/ecoff.h"		/* COFF-like aspects of ecoff files.  */ | 
|  |  | 
|  | #include "libaout.h"		/* Private BFD a.out information.  */ | 
|  | #include "aout/aout64.h" | 
|  | #include "aout/stab_gnu.h"	/* STABS information.  */ | 
|  |  | 
|  | #include "expression.h" | 
|  |  | 
|  | #include <algorithm> | 
|  |  | 
|  | /* Provide a way to test if we have both ECOFF and ELF symbol tables. | 
|  | We use this define in order to know whether we should override a | 
|  | symbol's ECOFF section with its ELF section.  This is necessary in | 
|  | case the symbol's ELF section could not be represented in ECOFF.  */ | 
|  | #define ECOFF_IN_ELF(bfd) (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ | 
|  | && bfd_get_section_by_name (bfd, ".mdebug") != NULL) | 
|  |  | 
|  | /* The objfile we are currently reading.  */ | 
|  |  | 
|  | static struct objfile *mdebugread_objfile; | 
|  |  | 
|  |  | 
|  |  | 
|  | /* We put a pointer to this structure in the read_symtab_private field | 
|  | of the psymtab.  */ | 
|  |  | 
|  | struct symloc | 
|  | { | 
|  | /* Index of the FDR that this psymtab represents.  */ | 
|  | int fdr_idx; | 
|  | /* The BFD that the psymtab was created from.  */ | 
|  | bfd *cur_bfd; | 
|  | const struct ecoff_debug_swap *debug_swap; | 
|  | struct ecoff_debug_info *debug_info; | 
|  | struct mdebug_pending **pending_list; | 
|  | /* Pointer to external symbols for this file.  */ | 
|  | EXTR *extern_tab; | 
|  | /* Size of extern_tab.  */ | 
|  | int extern_count; | 
|  | enum language pst_language; | 
|  | }; | 
|  |  | 
|  | #define PST_PRIVATE(p) ((struct symloc *)(p)->read_symtab_private) | 
|  | #define FDR_IDX(p) (PST_PRIVATE(p)->fdr_idx) | 
|  | #define CUR_BFD(p) (PST_PRIVATE(p)->cur_bfd) | 
|  | #define DEBUG_SWAP(p) (PST_PRIVATE(p)->debug_swap) | 
|  | #define DEBUG_INFO(p) (PST_PRIVATE(p)->debug_info) | 
|  | #define PENDING_LIST(p) (PST_PRIVATE(p)->pending_list) | 
|  |  | 
|  | #define SC_IS_TEXT(sc) ((sc) == scText \ | 
|  | || (sc) == scRConst \ | 
|  | || (sc) == scInit \ | 
|  | || (sc) == scFini) | 
|  | #define SC_IS_DATA(sc) ((sc) == scData \ | 
|  | || (sc) == scSData \ | 
|  | || (sc) == scRData \ | 
|  | || (sc) == scPData \ | 
|  | || (sc) == scXData) | 
|  | #define SC_IS_COMMON(sc) ((sc) == scCommon || (sc) == scSCommon) | 
|  | #define SC_IS_BSS(sc) ((sc) == scBss) | 
|  | #define SC_IS_SBSS(sc) ((sc) == scSBss) | 
|  | #define SC_IS_UNDEF(sc) ((sc) == scUndefined || (sc) == scSUndefined) | 
|  |  | 
|  | /* Various complaints about symbol reading that don't abort the process.  */ | 
|  | static void | 
|  | index_complaint (const char *arg1) | 
|  | { | 
|  | complaint (_("bad aux index at symbol %s"), arg1); | 
|  | } | 
|  |  | 
|  | static void | 
|  | unknown_ext_complaint (const char *arg1) | 
|  | { | 
|  | complaint (_("unknown external symbol %s"), arg1); | 
|  | } | 
|  |  | 
|  | static void | 
|  | basic_type_complaint (int arg1, const char *arg2) | 
|  | { | 
|  | complaint (_("cannot map ECOFF basic type 0x%x for %s"), | 
|  | arg1, arg2); | 
|  | } | 
|  |  | 
|  | static void | 
|  | bad_tag_guess_complaint (const char *arg1) | 
|  | { | 
|  | complaint (_("guessed tag type of %s incorrectly"), arg1); | 
|  | } | 
|  |  | 
|  | static void | 
|  | bad_rfd_entry_complaint (const char *arg1, int arg2, int arg3) | 
|  | { | 
|  | complaint (_("bad rfd entry for %s: file %d, index %d"), | 
|  | arg1, arg2, arg3); | 
|  | } | 
|  |  | 
|  | static void | 
|  | unexpected_type_code_complaint (const char *arg1) | 
|  | { | 
|  | complaint (_("unexpected type code for %s"), arg1); | 
|  | } | 
|  |  | 
|  | /* Macros and extra defs.  */ | 
|  |  | 
|  | /* Puns: hard to find whether -g was used and how.  */ | 
|  |  | 
|  | #define MIN_GLEVEL GLEVEL_0 | 
|  | #define compare_glevel(a,b)					\ | 
|  | (((a) == GLEVEL_3) ? ((b) < GLEVEL_3) :			\ | 
|  | ((b) == GLEVEL_3) ? -1 : (int)((b) - (a))) | 
|  |  | 
|  | /* Things that really are local to this module.  */ | 
|  |  | 
|  | /* Remember what we deduced to be the source language of this psymtab.  */ | 
|  |  | 
|  | static enum language psymtab_language = language_unknown; | 
|  |  | 
|  | /* Current BFD.  */ | 
|  |  | 
|  | static bfd *cur_bfd; | 
|  |  | 
|  | /* How to parse debugging information for CUR_BFD.  */ | 
|  |  | 
|  | static const struct ecoff_debug_swap *debug_swap; | 
|  |  | 
|  | /* Pointers to debugging information for CUR_BFD.  */ | 
|  |  | 
|  | static struct ecoff_debug_info *debug_info; | 
|  |  | 
|  | /* Pointer to current file descriptor record, and its index.  */ | 
|  |  | 
|  | static FDR *cur_fdr; | 
|  | static int cur_fd; | 
|  |  | 
|  | /* Index of current symbol.  */ | 
|  |  | 
|  | static int cur_sdx; | 
|  |  | 
|  | /* Note how much "debuggable" this image is.  We would like | 
|  | to see at least one FDR with full symbols.  */ | 
|  |  | 
|  | static int max_gdbinfo; | 
|  | static int max_glevel; | 
|  |  | 
|  | /* When examining .o files, report on undefined symbols.  */ | 
|  |  | 
|  | static int n_undef_symbols, n_undef_labels, n_undef_vars, n_undef_procs; | 
|  |  | 
|  | /* Pseudo symbol to use when putting stabs into the symbol table.  */ | 
|  |  | 
|  | static char stabs_symbol[] = STABS_SYMBOL; | 
|  |  | 
|  | /* Nonzero if we have seen ecoff debugging info for a file.  */ | 
|  |  | 
|  | static int found_ecoff_debugging_info; | 
|  |  | 
|  | /* Forward declarations.  */ | 
|  |  | 
|  | static int upgrade_type (int, struct type **, int, union aux_ext *, | 
|  | int, const char *); | 
|  |  | 
|  | static void parse_partial_symbols (minimal_symbol_reader &, | 
|  | psymtab_storage *, | 
|  | struct objfile *); | 
|  |  | 
|  | static int has_opaque_xref (FDR *, SYMR *); | 
|  |  | 
|  | static int cross_ref (int, union aux_ext *, struct type **, enum type_code, | 
|  | const char **, int, const char *); | 
|  |  | 
|  | static struct symbol *new_symbol (const char *); | 
|  |  | 
|  | static struct type *new_type (char *); | 
|  |  | 
|  | enum block_type { FUNCTION_BLOCK, NON_FUNCTION_BLOCK }; | 
|  |  | 
|  | static struct block *new_block (enum block_type, enum language); | 
|  |  | 
|  | static struct compunit_symtab *new_symtab (const char *, int, struct objfile *); | 
|  |  | 
|  | static struct linetable *new_linetable (int); | 
|  |  | 
|  | static struct blockvector *new_bvect (int); | 
|  |  | 
|  | static struct type *parse_type (int, union aux_ext *, unsigned int, int *, | 
|  | int, const char *); | 
|  |  | 
|  | static struct symbol *mylookup_symbol (const char *, const struct block *, | 
|  | domain_enum, enum address_class); | 
|  |  | 
|  | static void sort_blocks (struct symtab *); | 
|  |  | 
|  | static legacy_psymtab *new_psymtab (const char *, psymtab_storage *, | 
|  | struct objfile *); | 
|  |  | 
|  | static void mdebug_expand_psymtab (legacy_psymtab *pst, | 
|  | struct objfile *objfile); | 
|  |  | 
|  | static void add_block (struct block *, struct symtab *); | 
|  |  | 
|  | static void add_symbol (struct symbol *, struct symtab *, struct block *); | 
|  |  | 
|  | static int add_line (struct linetable *, int, CORE_ADDR, int); | 
|  |  | 
|  | static struct linetable *shrink_linetable (struct linetable *); | 
|  |  | 
|  | static void handle_psymbol_enumerators (struct objfile *, psymtab_storage *, | 
|  | partial_symtab *, | 
|  | FDR *, int, CORE_ADDR); | 
|  |  | 
|  | static const char *mdebug_next_symbol_text (struct objfile *); | 
|  |  | 
|  | /* Exported procedure: Builds a symtab from the partial symtab SELF. | 
|  | Restores the environment in effect when SELF was created, delegates | 
|  | most of the work to an ancillary procedure, and sorts | 
|  | and reorders the symtab list at the end.  SELF is not NULL.  */ | 
|  |  | 
|  | static void | 
|  | mdebug_read_symtab (legacy_psymtab *self, struct objfile *objfile) | 
|  | { | 
|  | next_symbol_text_func = mdebug_next_symbol_text; | 
|  |  | 
|  | self->expand_psymtab (objfile); | 
|  |  | 
|  | /* Match with global symbols.  This only needs to be done once, | 
|  | after all of the symtabs and dependencies have been read in.  */ | 
|  | scan_file_globals (objfile); | 
|  | } | 
|  |  | 
|  | /* File-level interface functions.  */ | 
|  |  | 
|  | /* Find a file descriptor given its index RF relative to a file CF.  */ | 
|  |  | 
|  | static FDR * | 
|  | get_rfd (int cf, int rf) | 
|  | { | 
|  | FDR *fdrs; | 
|  | FDR *f; | 
|  | RFDT rfd; | 
|  |  | 
|  | fdrs = debug_info->fdr; | 
|  | f = fdrs + cf; | 
|  | /* Object files do not have the RFD table, all refs are absolute.  */ | 
|  | if (f->rfdBase == 0) | 
|  | return fdrs + rf; | 
|  | (*debug_swap->swap_rfd_in) (cur_bfd, | 
|  | ((char *) debug_info->external_rfd | 
|  | + ((f->rfdBase + rf) | 
|  | * debug_swap->external_rfd_size)), | 
|  | &rfd); | 
|  | return fdrs + rfd; | 
|  | } | 
|  |  | 
|  | /* Return a safer print NAME for a file descriptor.  */ | 
|  |  | 
|  | static const char * | 
|  | fdr_name (FDR *f) | 
|  | { | 
|  | if (f->rss == -1) | 
|  | return "<stripped file>"; | 
|  | if (f->rss == 0) | 
|  | return "<NFY>"; | 
|  | return debug_info->ss + f->issBase + f->rss; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Read in and parse the symtab of the file OBJFILE.  Symbols from | 
|  | different sections are relocated via the SECTION_OFFSETS.  */ | 
|  |  | 
|  | void | 
|  | mdebug_build_psymtabs (minimal_symbol_reader &reader, | 
|  | struct objfile *objfile, | 
|  | const struct ecoff_debug_swap *swap, | 
|  | struct ecoff_debug_info *info) | 
|  | { | 
|  | cur_bfd = objfile->obfd; | 
|  | debug_swap = swap; | 
|  | debug_info = info; | 
|  |  | 
|  | stabsread_new_init (); | 
|  | free_header_files (); | 
|  | init_header_files (); | 
|  |  | 
|  | /* Make sure all the FDR information is swapped in.  */ | 
|  | if (info->fdr == NULL) | 
|  | { | 
|  | char *fdr_src; | 
|  | char *fdr_end; | 
|  | FDR *fdr_ptr; | 
|  |  | 
|  | info->fdr = (FDR *) XOBNEWVEC (&objfile->objfile_obstack, FDR, | 
|  | info->symbolic_header.ifdMax); | 
|  | fdr_src = (char *) info->external_fdr; | 
|  | fdr_end = (fdr_src | 
|  | + info->symbolic_header.ifdMax * swap->external_fdr_size); | 
|  | fdr_ptr = info->fdr; | 
|  | for (; fdr_src < fdr_end; fdr_src += swap->external_fdr_size, fdr_ptr++) | 
|  | (*swap->swap_fdr_in) (objfile->obfd, fdr_src, fdr_ptr); | 
|  | } | 
|  |  | 
|  | psymbol_functions *psf = new psymbol_functions (); | 
|  | psymtab_storage *partial_symtabs = psf->get_partial_symtabs ().get (); | 
|  | objfile->qf.emplace_front (psf); | 
|  | parse_partial_symbols (reader, partial_symtabs, objfile); | 
|  |  | 
|  | #if 0 | 
|  | /* Check to make sure file was compiled with -g.  If not, warn the | 
|  | user of this limitation.  */ | 
|  | if (compare_glevel (max_glevel, GLEVEL_2) < 0) | 
|  | { | 
|  | if (max_gdbinfo == 0) | 
|  | gdb_printf (_("\n%s not compiled with -g, " | 
|  | "debugging support is limited.\n"), | 
|  | objfile->name); | 
|  | gdb_printf (_("You should compile with -g2 or " | 
|  | "-g3 for best debugging support.\n")); | 
|  | } | 
|  | #endif | 
|  | } | 
|  |  | 
|  | /* Local utilities */ | 
|  |  | 
|  | /* Map of FDR indexes to partial symtabs.  */ | 
|  |  | 
|  | struct pst_map | 
|  | { | 
|  | legacy_psymtab *pst = nullptr;  /* the psymtab proper */ | 
|  | long n_globals = 0;		  /* exported globals (external symbols) */ | 
|  | long globals_offset = 0;	  /* cumulative */ | 
|  | }; | 
|  |  | 
|  |  | 
|  | /* Utility stack, used to nest procedures and blocks properly. | 
|  | It is a doubly linked list, to avoid too many alloc/free. | 
|  | Since we might need it quite a few times it is NOT deallocated | 
|  | after use.  */ | 
|  |  | 
|  | static struct parse_stack | 
|  | { | 
|  | struct parse_stack *next, *prev; | 
|  | struct symtab *cur_st;	/* Current symtab.  */ | 
|  | struct block *cur_block;	/* Block in it.  */ | 
|  |  | 
|  | /* What are we parsing.  stFile, or stBlock are for files and | 
|  | blocks.  stProc or stStaticProc means we have seen the start of a | 
|  | procedure, but not the start of the block within in.  When we see | 
|  | the start of that block, we change it to stNil, without pushing a | 
|  | new block, i.e. stNil means both a procedure and a block.  */ | 
|  |  | 
|  | int blocktype; | 
|  |  | 
|  | struct type *cur_type;	/* Type we parse fields for.  */ | 
|  | int cur_field;		/* Field number in cur_type.  */ | 
|  | CORE_ADDR procadr;		/* Start addres of this procedure.  */ | 
|  | int numargs;		/* Its argument count.  */ | 
|  | } | 
|  |  | 
|  | *top_stack;			/* Top stack ptr */ | 
|  |  | 
|  |  | 
|  | /* Enter a new lexical context.  */ | 
|  |  | 
|  | static void | 
|  | push_parse_stack (void) | 
|  | { | 
|  | struct parse_stack *newobj; | 
|  |  | 
|  | /* Reuse frames if possible.  */ | 
|  | if (top_stack && top_stack->prev) | 
|  | newobj = top_stack->prev; | 
|  | else | 
|  | newobj = XCNEW (struct parse_stack); | 
|  | /* Initialize new frame with previous content.  */ | 
|  | if (top_stack) | 
|  | { | 
|  | struct parse_stack *prev = newobj->prev; | 
|  |  | 
|  | *newobj = *top_stack; | 
|  | top_stack->prev = newobj; | 
|  | newobj->prev = prev; | 
|  | newobj->next = top_stack; | 
|  | } | 
|  | top_stack = newobj; | 
|  | } | 
|  |  | 
|  | /* Exit a lexical context.  */ | 
|  |  | 
|  | static void | 
|  | pop_parse_stack (void) | 
|  | { | 
|  | if (!top_stack) | 
|  | return; | 
|  | if (top_stack->next) | 
|  | top_stack = top_stack->next; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Cross-references might be to things we haven't looked at | 
|  | yet, e.g. type references.  To avoid too many type | 
|  | duplications we keep a quick fixup table, an array | 
|  | of lists of references indexed by file descriptor.  */ | 
|  |  | 
|  | struct mdebug_pending | 
|  | { | 
|  | struct mdebug_pending *next;	/* link */ | 
|  | char *s;			/* the unswapped symbol */ | 
|  | struct type *t;		/* its partial type descriptor */ | 
|  | }; | 
|  |  | 
|  |  | 
|  | /* The pending information is kept for an entire object file.  We | 
|  | allocate the pending information table when we create the partial | 
|  | symbols, and we store a pointer to the single table in each | 
|  | psymtab.  */ | 
|  |  | 
|  | static struct mdebug_pending **pending_list; | 
|  |  | 
|  | /* Check whether we already saw symbol SH in file FH.  */ | 
|  |  | 
|  | static struct mdebug_pending * | 
|  | is_pending_symbol (FDR *fh, char *sh) | 
|  | { | 
|  | int f_idx = fh - debug_info->fdr; | 
|  | struct mdebug_pending *p; | 
|  |  | 
|  | /* Linear search is ok, list is typically no more than 10 deep.  */ | 
|  | for (p = pending_list[f_idx]; p; p = p->next) | 
|  | if (p->s == sh) | 
|  | break; | 
|  | return p; | 
|  | } | 
|  |  | 
|  | /* Add a new symbol SH of type T.  */ | 
|  |  | 
|  | static void | 
|  | add_pending (FDR *fh, char *sh, struct type *t) | 
|  | { | 
|  | int f_idx = fh - debug_info->fdr; | 
|  | struct mdebug_pending *p = is_pending_symbol (fh, sh); | 
|  |  | 
|  | /* Make sure we do not make duplicates.  */ | 
|  | if (!p) | 
|  | { | 
|  | p = XOBNEW (&mdebugread_objfile->objfile_obstack, mdebug_pending); | 
|  | p->s = sh; | 
|  | p->t = t; | 
|  | p->next = pending_list[f_idx]; | 
|  | pending_list[f_idx] = p; | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Parsing Routines proper.  */ | 
|  |  | 
|  | static void | 
|  | reg_value_complaint (int regnum, int num_regs, const char *sym) | 
|  | { | 
|  | complaint (_("bad register number %d (max %d) in symbol %s"), | 
|  | regnum, num_regs - 1, sym); | 
|  | } | 
|  |  | 
|  | /* Parse a single symbol.  Mostly just make up a GDB symbol for it. | 
|  | For blocks, procedures and types we open a new lexical context. | 
|  | This is basically just a big switch on the symbol's type.  Argument | 
|  | AX is the base pointer of aux symbols for this file (fh->iauxBase). | 
|  | EXT_SH points to the unswapped symbol, which is needed for struct, | 
|  | union, etc., types; it is NULL for an EXTR.  BIGEND says whether | 
|  | aux symbols are big-endian or little-endian.  Return count of | 
|  | SYMR's handled (normally one).  */ | 
|  |  | 
|  | static int | 
|  | mdebug_reg_to_regnum (struct symbol *sym, struct gdbarch *gdbarch) | 
|  | { | 
|  | int regno = gdbarch_ecoff_reg_to_regnum (gdbarch, sym->value_longest ()); | 
|  |  | 
|  | if (regno < 0 || regno >= gdbarch_num_cooked_regs (gdbarch)) | 
|  | { | 
|  | reg_value_complaint (regno, gdbarch_num_cooked_regs (gdbarch), | 
|  | sym->print_name ()); | 
|  |  | 
|  | regno = gdbarch_sp_regnum (gdbarch); /* Known safe, though useless.  */ | 
|  | } | 
|  |  | 
|  | return regno; | 
|  | } | 
|  |  | 
|  | static const struct symbol_register_ops mdebug_register_funcs = { | 
|  | mdebug_reg_to_regnum | 
|  | }; | 
|  |  | 
|  | /* The "aclass" indices for computed symbols.  */ | 
|  |  | 
|  | static int mdebug_register_index; | 
|  | static int mdebug_regparm_index; | 
|  |  | 
|  | /* Common code for symbols describing data.  */ | 
|  |  | 
|  | static void | 
|  | add_data_symbol (SYMR *sh, union aux_ext *ax, int bigend, | 
|  | struct symbol *s, int aclass_index, struct block *b, | 
|  | struct objfile *objfile, const char *name) | 
|  | { | 
|  | s->set_domain (VAR_DOMAIN); | 
|  | s->set_aclass_index (aclass_index); | 
|  | add_symbol (s, top_stack->cur_st, b); | 
|  |  | 
|  | /* Type could be missing if file is compiled without debugging info.  */ | 
|  | if (SC_IS_UNDEF (sh->sc) | 
|  | || sh->sc == scNil || sh->index == indexNil) | 
|  | s->set_type (objfile_type (objfile)->nodebug_data_symbol); | 
|  | else | 
|  | s->set_type (parse_type (cur_fd, ax, sh->index, 0, bigend, name)); | 
|  | /* Value of a data symbol is its memory address.  */ | 
|  | } | 
|  |  | 
|  | static int | 
|  | parse_symbol (SYMR *sh, union aux_ext *ax, char *ext_sh, int bigend, | 
|  | const section_offsets §ion_offsets, struct objfile *objfile) | 
|  | { | 
|  | struct gdbarch *gdbarch = objfile->arch (); | 
|  | const bfd_size_type external_sym_size = debug_swap->external_sym_size; | 
|  | void (*const swap_sym_in) (bfd *, void *, SYMR *) = debug_swap->swap_sym_in; | 
|  | const char *name; | 
|  | struct symbol *s; | 
|  | struct block *b; | 
|  | struct mdebug_pending *pend; | 
|  | struct type *t; | 
|  | int count = 1; | 
|  | TIR tir; | 
|  | long svalue = sh->value; | 
|  | int bitsize; | 
|  |  | 
|  | if (ext_sh == NULL) | 
|  | name = debug_info->ssext + sh->iss; | 
|  | else | 
|  | name = debug_info->ss + cur_fdr->issBase + sh->iss; | 
|  |  | 
|  | switch (sh->sc) | 
|  | { | 
|  | case scText: | 
|  | case scRConst: | 
|  | /* Do not relocate relative values. | 
|  | The value of a stEnd symbol is the displacement from the | 
|  | corresponding start symbol value. | 
|  | The value of a stBlock symbol is the displacement from the | 
|  | procedure address.  */ | 
|  | if (sh->st != stEnd && sh->st != stBlock) | 
|  | sh->value += section_offsets[SECT_OFF_TEXT (objfile)]; | 
|  | break; | 
|  | case scData: | 
|  | case scSData: | 
|  | case scRData: | 
|  | case scPData: | 
|  | case scXData: | 
|  | sh->value += section_offsets[SECT_OFF_DATA (objfile)]; | 
|  | break; | 
|  | case scBss: | 
|  | case scSBss: | 
|  | sh->value += section_offsets[SECT_OFF_BSS (objfile)]; | 
|  | break; | 
|  | } | 
|  |  | 
|  | switch (sh->st) | 
|  | { | 
|  | case stNil: | 
|  | break; | 
|  |  | 
|  | case stGlobal:		/* External symbol, goes into global block.  */ | 
|  | b = BLOCKVECTOR_BLOCK (top_stack->cur_st->compunit ()->blockvector (), | 
|  | GLOBAL_BLOCK); | 
|  | s = new_symbol (name); | 
|  | s->set_value_address (sh->value); | 
|  | add_data_symbol (sh, ax, bigend, s, LOC_STATIC, b, objfile, name); | 
|  | break; | 
|  |  | 
|  | case stStatic:		/* Static data, goes into current block.  */ | 
|  | b = top_stack->cur_block; | 
|  | s = new_symbol (name); | 
|  | if (SC_IS_COMMON (sh->sc)) | 
|  | { | 
|  | /* It is a FORTRAN common block.  At least for SGI Fortran the | 
|  | address is not in the symbol; we need to fix it later in | 
|  | scan_file_globals.  */ | 
|  | int bucket = hashname (s->linkage_name ()); | 
|  | s->set_value_chain (global_sym_chain[bucket]); | 
|  | global_sym_chain[bucket] = s; | 
|  | } | 
|  | else | 
|  | s->set_value_address (sh->value); | 
|  | add_data_symbol (sh, ax, bigend, s, LOC_STATIC, b, objfile, name); | 
|  | break; | 
|  |  | 
|  | case stLocal:		/* Local variable, goes into current block.  */ | 
|  | b = top_stack->cur_block; | 
|  | s = new_symbol (name); | 
|  | s->set_value_longest (svalue); | 
|  | if (sh->sc == scRegister) | 
|  | add_data_symbol (sh, ax, bigend, s, mdebug_register_index, | 
|  | b, objfile, name); | 
|  | else | 
|  | add_data_symbol (sh, ax, bigend, s, LOC_LOCAL, | 
|  | b, objfile, name); | 
|  | break; | 
|  |  | 
|  | case stParam:		/* Arg to procedure, goes into current | 
|  | block.  */ | 
|  | max_gdbinfo++; | 
|  | found_ecoff_debugging_info = 1; | 
|  | top_stack->numargs++; | 
|  |  | 
|  | /* Special GNU C++ name.  */ | 
|  | if (is_cplus_marker (name[0]) && name[1] == 't' && name[2] == 0) | 
|  | name = "this";		/* FIXME, not alloc'd in obstack.  */ | 
|  | s = new_symbol (name); | 
|  |  | 
|  | s->set_domain (VAR_DOMAIN); | 
|  | s->set_is_argument (1); | 
|  | switch (sh->sc) | 
|  | { | 
|  | case scRegister: | 
|  | /* Pass by value in register.  */ | 
|  | s->set_aclass_index (mdebug_register_index); | 
|  | break; | 
|  | case scVar: | 
|  | /* Pass by reference on stack.  */ | 
|  | s->set_aclass_index (LOC_REF_ARG); | 
|  | break; | 
|  | case scVarRegister: | 
|  | /* Pass by reference in register.  */ | 
|  | s->set_aclass_index (mdebug_regparm_index); | 
|  | break; | 
|  | default: | 
|  | /* Pass by value on stack.  */ | 
|  | s->set_aclass_index (LOC_ARG); | 
|  | break; | 
|  | } | 
|  | s->set_value_longest (svalue); | 
|  | s->set_type (parse_type (cur_fd, ax, sh->index, 0, bigend, name)); | 
|  | add_symbol (s, top_stack->cur_st, top_stack->cur_block); | 
|  | break; | 
|  |  | 
|  | case stLabel:		/* label, goes into current block.  */ | 
|  | s = new_symbol (name); | 
|  | s->set_domain (VAR_DOMAIN);	/* So that it can be used */ | 
|  | s->set_aclass_index (LOC_LABEL);	/* but not misused.  */ | 
|  | s->set_value_address (sh->value); | 
|  | s->set_type (objfile_type (objfile)->builtin_int); | 
|  | add_symbol (s, top_stack->cur_st, top_stack->cur_block); | 
|  | break; | 
|  |  | 
|  | case stProc:	/* Procedure, usually goes into global block.  */ | 
|  | case stStaticProc:	/* Static procedure, goes into current block.  */ | 
|  | /* For stProc symbol records, we need to check the storage class | 
|  | as well, as only (stProc, scText) entries represent "real" | 
|  | procedures - See the Compaq document titled "Object File / | 
|  | Symbol Table Format Specification" for more information. | 
|  | If the storage class is not scText, we discard the whole block | 
|  | of symbol records for this stProc.  */ | 
|  | if (sh->st == stProc && sh->sc != scText) | 
|  | { | 
|  | char *ext_tsym = ext_sh; | 
|  | int keep_counting = 1; | 
|  | SYMR tsym; | 
|  |  | 
|  | while (keep_counting) | 
|  | { | 
|  | ext_tsym += external_sym_size; | 
|  | (*swap_sym_in) (cur_bfd, ext_tsym, &tsym); | 
|  | count++; | 
|  | switch (tsym.st) | 
|  | { | 
|  | case stParam: | 
|  | break; | 
|  | case stEnd: | 
|  | keep_counting = 0; | 
|  | break; | 
|  | default: | 
|  | complaint (_("unknown symbol type 0x%x"), sh->st); | 
|  | break; | 
|  | } | 
|  | } | 
|  | break; | 
|  | } | 
|  | s = new_symbol (name); | 
|  | s->set_domain (VAR_DOMAIN); | 
|  | s->set_aclass_index (LOC_BLOCK); | 
|  | /* Type of the return value.  */ | 
|  | if (SC_IS_UNDEF (sh->sc) || sh->sc == scNil) | 
|  | t = objfile_type (objfile)->builtin_int; | 
|  | else | 
|  | { | 
|  | t = parse_type (cur_fd, ax, sh->index + 1, 0, bigend, name); | 
|  | if (strcmp (name, "malloc") == 0 | 
|  | && t->code () == TYPE_CODE_VOID) | 
|  | { | 
|  | /* I don't know why, but, at least under Alpha GNU/Linux, | 
|  | when linking against a malloc without debugging | 
|  | symbols, its read as a function returning void---this | 
|  | is bad because it means we cannot call functions with | 
|  | string arguments interactively; i.e., "call | 
|  | printf("howdy\n")" would fail with the error message | 
|  | "program has no memory available".  To avoid this, we | 
|  | patch up the type and make it void* | 
|  | instead. (davidm@azstarnet.com).  */ | 
|  | t = make_pointer_type (t, NULL); | 
|  | } | 
|  | } | 
|  | b = top_stack->cur_block; | 
|  | if (sh->st == stProc) | 
|  | { | 
|  | const struct blockvector *bv | 
|  | = top_stack->cur_st->compunit ()->blockvector (); | 
|  |  | 
|  | /* The next test should normally be true, but provides a | 
|  | hook for nested functions (which we don't want to make | 
|  | global).  */ | 
|  | if (b == BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)) | 
|  | b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); | 
|  | /* Irix 5 sometimes has duplicate names for the same | 
|  | function.  We want to add such names up at the global | 
|  | level, not as a nested function.  */ | 
|  | else if (sh->value == top_stack->procadr) | 
|  | b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); | 
|  | } | 
|  | add_symbol (s, top_stack->cur_st, b); | 
|  |  | 
|  | /* Make a type for the procedure itself.  */ | 
|  | s->set_type (lookup_function_type (t)); | 
|  |  | 
|  | /* All functions in C++ have prototypes.  For C we don't have enough | 
|  | information in the debug info.  */ | 
|  | if (s->language () == language_cplus) | 
|  | s->type ()->set_is_prototyped (true); | 
|  |  | 
|  | /* Create and enter a new lexical context.  */ | 
|  | b = new_block (FUNCTION_BLOCK, s->language ()); | 
|  | s->set_value_block (b); | 
|  | BLOCK_FUNCTION (b) = s; | 
|  | BLOCK_START (b) = BLOCK_END (b) = sh->value; | 
|  | BLOCK_SUPERBLOCK (b) = top_stack->cur_block; | 
|  | add_block (b, top_stack->cur_st); | 
|  |  | 
|  | /* Not if we only have partial info.  */ | 
|  | if (SC_IS_UNDEF (sh->sc) || sh->sc == scNil) | 
|  | break; | 
|  |  | 
|  | push_parse_stack (); | 
|  | top_stack->cur_block = b; | 
|  | top_stack->blocktype = sh->st; | 
|  | top_stack->cur_type = s->type (); | 
|  | top_stack->cur_field = -1; | 
|  | top_stack->procadr = sh->value; | 
|  | top_stack->numargs = 0; | 
|  | break; | 
|  |  | 
|  | /* Beginning of code for structure, union, and enum definitions. | 
|  | They all share a common set of local variables, defined here.  */ | 
|  | { | 
|  | enum type_code type_code; | 
|  | char *ext_tsym; | 
|  | int nfields; | 
|  | long max_value; | 
|  | struct field *f; | 
|  |  | 
|  | case stStruct:		/* Start a block defining a struct type.  */ | 
|  | type_code = TYPE_CODE_STRUCT; | 
|  | goto structured_common; | 
|  |  | 
|  | case stUnion:		/* Start a block defining a union type.  */ | 
|  | type_code = TYPE_CODE_UNION; | 
|  | goto structured_common; | 
|  |  | 
|  | case stEnum:		/* Start a block defining an enum type.  */ | 
|  | type_code = TYPE_CODE_ENUM; | 
|  | goto structured_common; | 
|  |  | 
|  | case stBlock:		/* Either a lexical block, or some type.  */ | 
|  | if (sh->sc != scInfo && !SC_IS_COMMON (sh->sc)) | 
|  | goto case_stBlock_code;	/* Lexical block */ | 
|  |  | 
|  | type_code = TYPE_CODE_UNDEF;	/* We have a type.  */ | 
|  |  | 
|  | /* Common code for handling struct, union, enum, and/or as-yet- | 
|  | unknown-type blocks of info about structured data.  `type_code' | 
|  | has been set to the proper TYPE_CODE, if we know it.  */ | 
|  | structured_common: | 
|  | found_ecoff_debugging_info = 1; | 
|  | push_parse_stack (); | 
|  | top_stack->blocktype = stBlock; | 
|  |  | 
|  | /* First count the number of fields and the highest value.  */ | 
|  | nfields = 0; | 
|  | max_value = 0; | 
|  | for (ext_tsym = ext_sh + external_sym_size; | 
|  | ; | 
|  | ext_tsym += external_sym_size) | 
|  | { | 
|  | SYMR tsym; | 
|  |  | 
|  | (*swap_sym_in) (cur_bfd, ext_tsym, &tsym); | 
|  |  | 
|  | switch (tsym.st) | 
|  | { | 
|  | case stEnd: | 
|  | /* C++ encodes class types as structures where there the | 
|  | methods are encoded as stProc.  The scope of stProc | 
|  | symbols also ends with stEnd, thus creating a risk of | 
|  | taking the wrong stEnd symbol record as the end of | 
|  | the current struct, which would cause GDB to undercount | 
|  | the real number of fields in this struct.  To make sure | 
|  | we really reached the right stEnd symbol record, we | 
|  | check the associated name, and match it against the | 
|  | struct name.  Since method names are mangled while | 
|  | the class name is not, there is no risk of having a | 
|  | method whose name is identical to the class name | 
|  | (in particular constructor method names are different | 
|  | from the class name).  There is therefore no risk that | 
|  | this check stops the count on the StEnd of a method. | 
|  |  | 
|  | Also, assume that we're really at the end when tsym.iss | 
|  | is 0 (issNull).  */ | 
|  | if (tsym.iss == issNull | 
|  | || strcmp (debug_info->ss + cur_fdr->issBase + tsym.iss, | 
|  | name) == 0) | 
|  | goto end_of_fields; | 
|  | break; | 
|  |  | 
|  | case stMember: | 
|  | if (nfields == 0 && type_code == TYPE_CODE_UNDEF) | 
|  | { | 
|  | /* If the type of the member is Nil (or Void), | 
|  | without qualifiers, assume the tag is an | 
|  | enumeration. | 
|  | Alpha cc -migrate enums are recognized by a zero | 
|  | index and a zero symbol value. | 
|  | DU 4.0 cc enums are recognized by a member type of | 
|  | btEnum without qualifiers and a zero symbol value.  */ | 
|  | if (tsym.index == indexNil | 
|  | || (tsym.index == 0 && sh->value == 0)) | 
|  | type_code = TYPE_CODE_ENUM; | 
|  | else | 
|  | { | 
|  | (*debug_swap->swap_tir_in) (bigend, | 
|  | &ax[tsym.index].a_ti, | 
|  | &tir); | 
|  | if ((tir.bt == btNil || tir.bt == btVoid | 
|  | || (tir.bt == btEnum && sh->value == 0)) | 
|  | && tir.tq0 == tqNil) | 
|  | type_code = TYPE_CODE_ENUM; | 
|  | } | 
|  | } | 
|  | nfields++; | 
|  | if (tsym.value > max_value) | 
|  | max_value = tsym.value; | 
|  | break; | 
|  |  | 
|  | case stBlock: | 
|  | case stUnion: | 
|  | case stEnum: | 
|  | case stStruct: | 
|  | { | 
|  | #if 0 | 
|  | /* This is a no-op; is it trying to tell us something | 
|  | we should be checking?  */ | 
|  | if (tsym.sc == scVariant);	/*UNIMPLEMENTED */ | 
|  | #endif | 
|  | if (tsym.index != 0) | 
|  | { | 
|  | /* This is something like a struct within a | 
|  | struct.  Skip over the fields of the inner | 
|  | struct.  The -1 is because the for loop will | 
|  | increment ext_tsym.  */ | 
|  | ext_tsym = ((char *) debug_info->external_sym | 
|  | + ((cur_fdr->isymBase + tsym.index - 1) | 
|  | * external_sym_size)); | 
|  | } | 
|  | } | 
|  | break; | 
|  |  | 
|  | case stTypedef: | 
|  | /* mips cc puts out a typedef for struct x if it is not yet | 
|  | defined when it encounters | 
|  | struct y { struct x *xp; }; | 
|  | Just ignore it.  */ | 
|  | break; | 
|  |  | 
|  | case stIndirect: | 
|  | /* Irix5 cc puts out a stIndirect for struct x if it is not | 
|  | yet defined when it encounters | 
|  | struct y { struct x *xp; }; | 
|  | Just ignore it.  */ | 
|  | break; | 
|  |  | 
|  | default: | 
|  | complaint (_("declaration block contains " | 
|  | "unhandled symbol type %d"), | 
|  | tsym.st); | 
|  | } | 
|  | } | 
|  | end_of_fields: | 
|  |  | 
|  | /* In an stBlock, there is no way to distinguish structs, | 
|  | unions, and enums at this point.  This is a bug in the | 
|  | original design (that has been fixed with the recent | 
|  | addition of the stStruct, stUnion, and stEnum symbol | 
|  | types.)  The way you can tell is if/when you see a variable | 
|  | or field of that type.  In that case the variable's type | 
|  | (in the AUX table) says if the type is struct, union, or | 
|  | enum, and points back to the stBlock here.  So you can | 
|  | patch the tag kind up later - but only if there actually is | 
|  | a variable or field of that type. | 
|  |  | 
|  | So until we know for sure, we will guess at this point. | 
|  | The heuristic is: | 
|  | If the first member has index==indexNil or a void type, | 
|  | assume we have an enumeration. | 
|  | Otherwise, if there is more than one member, and all | 
|  | the members have offset 0, assume we have a union. | 
|  | Otherwise, assume we have a struct. | 
|  |  | 
|  | The heuristic could guess wrong in the case of of an | 
|  | enumeration with no members or a union with one (or zero) | 
|  | members, or when all except the last field of a struct have | 
|  | width zero.  These are uncommon and/or illegal situations, | 
|  | and in any case guessing wrong probably doesn't matter | 
|  | much. | 
|  |  | 
|  | But if we later do find out we were wrong, we fixup the tag | 
|  | kind.  Members of an enumeration must be handled | 
|  | differently from struct/union fields, and that is harder to | 
|  | patch up, but luckily we shouldn't need to.  (If there are | 
|  | any enumeration members, we can tell for sure it's an enum | 
|  | here.)  */ | 
|  |  | 
|  | if (type_code == TYPE_CODE_UNDEF) | 
|  | { | 
|  | if (nfields > 1 && max_value == 0) | 
|  | type_code = TYPE_CODE_UNION; | 
|  | else | 
|  | type_code = TYPE_CODE_STRUCT; | 
|  | } | 
|  |  | 
|  | /* Create a new type or use the pending type.  */ | 
|  | pend = is_pending_symbol (cur_fdr, ext_sh); | 
|  | if (pend == NULL) | 
|  | { | 
|  | t = new_type (NULL); | 
|  | add_pending (cur_fdr, ext_sh, t); | 
|  | } | 
|  | else | 
|  | t = pend->t; | 
|  |  | 
|  | /* Do not set the tag name if it is a compiler generated tag name | 
|  | (.Fxx or .xxfake or empty) for unnamed struct/union/enums. | 
|  | Alpha cc puts out an sh->iss of zero for those.  */ | 
|  | if (sh->iss == 0 || name[0] == '.' || name[0] == '\0') | 
|  | t->set_name (NULL); | 
|  | else | 
|  | t->set_name (obconcat (&mdebugread_objfile->objfile_obstack, | 
|  | name, (char *) NULL)); | 
|  |  | 
|  | t->set_code (type_code); | 
|  | TYPE_LENGTH (t) = sh->value; | 
|  | t->set_num_fields (nfields); | 
|  | f = ((struct field *) TYPE_ALLOC (t, nfields * sizeof (struct field))); | 
|  | t->set_fields (f); | 
|  |  | 
|  | if (type_code == TYPE_CODE_ENUM) | 
|  | { | 
|  | int unsigned_enum = 1; | 
|  |  | 
|  | /* This is a non-empty enum.  */ | 
|  |  | 
|  | /* DEC c89 has the number of enumerators in the sh.value field, | 
|  | not the type length, so we have to compensate for that | 
|  | incompatibility quirk. | 
|  | This might do the wrong thing for an enum with one or two | 
|  | enumerators and gcc -gcoff -fshort-enums, but these cases | 
|  | are hopefully rare enough. | 
|  | Alpha cc -migrate has a sh.value field of zero, we adjust | 
|  | that too.  */ | 
|  | if (TYPE_LENGTH (t) == t->num_fields () | 
|  | || TYPE_LENGTH (t) == 0) | 
|  | TYPE_LENGTH (t) = gdbarch_int_bit (gdbarch) / HOST_CHAR_BIT; | 
|  | for (ext_tsym = ext_sh + external_sym_size; | 
|  | ; | 
|  | ext_tsym += external_sym_size) | 
|  | { | 
|  | SYMR tsym; | 
|  | struct symbol *enum_sym; | 
|  |  | 
|  | (*swap_sym_in) (cur_bfd, ext_tsym, &tsym); | 
|  |  | 
|  | if (tsym.st != stMember) | 
|  | break; | 
|  |  | 
|  | f->set_loc_enumval (tsym.value); | 
|  | f->set_type (t); | 
|  | f->set_name (debug_info->ss + cur_fdr->issBase + tsym.iss); | 
|  | FIELD_BITSIZE (*f) = 0; | 
|  |  | 
|  | enum_sym = new (&mdebugread_objfile->objfile_obstack) symbol; | 
|  | enum_sym->set_linkage_name | 
|  | (obstack_strdup (&mdebugread_objfile->objfile_obstack, | 
|  | f->name ())); | 
|  | enum_sym->set_aclass_index (LOC_CONST); | 
|  | enum_sym->set_type (t); | 
|  | enum_sym->set_domain (VAR_DOMAIN); | 
|  | enum_sym->set_value_longest (tsym.value); | 
|  | if (enum_sym->value_longest () < 0) | 
|  | unsigned_enum = 0; | 
|  | add_symbol (enum_sym, top_stack->cur_st, top_stack->cur_block); | 
|  |  | 
|  | /* Skip the stMembers that we've handled.  */ | 
|  | count++; | 
|  | f++; | 
|  | } | 
|  | if (unsigned_enum) | 
|  | t->set_is_unsigned (true); | 
|  | } | 
|  | /* Make this the current type.  */ | 
|  | top_stack->cur_type = t; | 
|  | top_stack->cur_field = 0; | 
|  |  | 
|  | /* Do not create a symbol for alpha cc unnamed structs.  */ | 
|  | if (sh->iss == 0) | 
|  | break; | 
|  |  | 
|  | /* gcc puts out an empty struct for an opaque struct definitions, | 
|  | do not create a symbol for it either.  */ | 
|  | if (t->num_fields () == 0) | 
|  | { | 
|  | t->set_is_stub (true); | 
|  | break; | 
|  | } | 
|  |  | 
|  | s = new_symbol (name); | 
|  | s->set_domain (STRUCT_DOMAIN); | 
|  | s->set_aclass_index (LOC_TYPEDEF); | 
|  | s->set_value_longest (0); | 
|  | s->set_type (t); | 
|  | add_symbol (s, top_stack->cur_st, top_stack->cur_block); | 
|  | break; | 
|  |  | 
|  | /* End of local variables shared by struct, union, enum, and | 
|  | block (as yet unknown struct/union/enum) processing.  */ | 
|  | } | 
|  |  | 
|  | case_stBlock_code: | 
|  | found_ecoff_debugging_info = 1; | 
|  | /* Beginnning of (code) block.  Value of symbol | 
|  | is the displacement from procedure start.  */ | 
|  | push_parse_stack (); | 
|  |  | 
|  | /* Do not start a new block if this is the outermost block of a | 
|  | procedure.  This allows the LOC_BLOCK symbol to point to the | 
|  | block with the local variables, so funcname::var works.  */ | 
|  | if (top_stack->blocktype == stProc | 
|  | || top_stack->blocktype == stStaticProc) | 
|  | { | 
|  | top_stack->blocktype = stNil; | 
|  | break; | 
|  | } | 
|  |  | 
|  | top_stack->blocktype = stBlock; | 
|  | b = new_block (NON_FUNCTION_BLOCK, psymtab_language); | 
|  | BLOCK_START (b) = sh->value + top_stack->procadr; | 
|  | BLOCK_SUPERBLOCK (b) = top_stack->cur_block; | 
|  | top_stack->cur_block = b; | 
|  | add_block (b, top_stack->cur_st); | 
|  | break; | 
|  |  | 
|  | case stEnd:		/* end (of anything) */ | 
|  | if (sh->sc == scInfo || SC_IS_COMMON (sh->sc)) | 
|  | { | 
|  | /* Finished with type */ | 
|  | top_stack->cur_type = 0; | 
|  | } | 
|  | else if (sh->sc == scText && | 
|  | (top_stack->blocktype == stProc || | 
|  | top_stack->blocktype == stStaticProc)) | 
|  | { | 
|  | /* Finished with procedure */ | 
|  | const struct blockvector *bv | 
|  | = top_stack->cur_st->compunit ()->blockvector (); | 
|  | struct mdebug_extra_func_info *e; | 
|  | struct block *cblock = top_stack->cur_block; | 
|  | struct type *ftype = top_stack->cur_type; | 
|  | int i; | 
|  |  | 
|  | BLOCK_END (top_stack->cur_block) += sh->value;	/* size */ | 
|  |  | 
|  | /* Make up special symbol to contain procedure specific info.  */ | 
|  | s = new_symbol (MDEBUG_EFI_SYMBOL_NAME); | 
|  | s->set_domain (LABEL_DOMAIN); | 
|  | s->set_aclass_index (LOC_CONST); | 
|  | s->set_type (objfile_type (mdebugread_objfile)->builtin_void); | 
|  | e = OBSTACK_ZALLOC (&mdebugread_objfile->objfile_obstack, | 
|  | mdebug_extra_func_info); | 
|  | s->set_value_bytes ((gdb_byte *) e); | 
|  | e->numargs = top_stack->numargs; | 
|  | e->pdr.framereg = -1; | 
|  | add_symbol (s, top_stack->cur_st, top_stack->cur_block); | 
|  |  | 
|  | /* f77 emits proc-level with address bounds==[0,0], | 
|  | So look for such child blocks, and patch them.  */ | 
|  | for (i = 0; i < BLOCKVECTOR_NBLOCKS (bv); i++) | 
|  | { | 
|  | struct block *b_bad = BLOCKVECTOR_BLOCK (bv, i); | 
|  |  | 
|  | if (BLOCK_SUPERBLOCK (b_bad) == cblock | 
|  | && BLOCK_START (b_bad) == top_stack->procadr | 
|  | && BLOCK_END (b_bad) == top_stack->procadr) | 
|  | { | 
|  | BLOCK_START (b_bad) = BLOCK_START (cblock); | 
|  | BLOCK_END (b_bad) = BLOCK_END (cblock); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (ftype->num_fields () <= 0) | 
|  | { | 
|  | /* No parameter type information is recorded with the function's | 
|  | type.  Set that from the type of the parameter symbols.  */ | 
|  | int nparams = top_stack->numargs; | 
|  | int iparams; | 
|  | struct symbol *sym; | 
|  |  | 
|  | if (nparams > 0) | 
|  | { | 
|  | struct block_iterator iter; | 
|  |  | 
|  | ftype->set_num_fields (nparams); | 
|  | ftype->set_fields | 
|  | ((struct field *) | 
|  | TYPE_ALLOC (ftype, nparams * sizeof (struct field))); | 
|  |  | 
|  | iparams = 0; | 
|  | ALL_BLOCK_SYMBOLS (cblock, iter, sym) | 
|  | { | 
|  | if (iparams == nparams) | 
|  | break; | 
|  |  | 
|  | if (sym->is_argument ()) | 
|  | { | 
|  | ftype->field (iparams).set_type (sym->type ()); | 
|  | TYPE_FIELD_ARTIFICIAL (ftype, iparams) = 0; | 
|  | iparams++; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | else if (sh->sc == scText && top_stack->blocktype == stBlock) | 
|  | { | 
|  | /* End of (code) block.  The value of the symbol is the | 
|  | displacement from the procedure`s start address of the | 
|  | end of this block.  */ | 
|  | BLOCK_END (top_stack->cur_block) = sh->value + top_stack->procadr; | 
|  | } | 
|  | else if (sh->sc == scText && top_stack->blocktype == stNil) | 
|  | { | 
|  | /* End of outermost block.  Pop parse stack and ignore.  The | 
|  | following stEnd of stProc will take care of the block.  */ | 
|  | ; | 
|  | } | 
|  | else if (sh->sc == scText && top_stack->blocktype == stFile) | 
|  | { | 
|  | /* End of file.  Pop parse stack and ignore.  Higher | 
|  | level code deals with this.  */ | 
|  | ; | 
|  | } | 
|  | else | 
|  | complaint (_("stEnd with storage class %d not handled"), sh->sc); | 
|  |  | 
|  | pop_parse_stack ();	/* Restore previous lexical context.  */ | 
|  | break; | 
|  |  | 
|  | case stMember:		/* member of struct or union */ | 
|  | { | 
|  | struct field *f = &top_stack->cur_type->field (top_stack->cur_field); | 
|  | top_stack->cur_field++; | 
|  | f->set_name (name); | 
|  | f->set_loc_bitpos (sh->value); | 
|  | bitsize = 0; | 
|  | f->set_type (parse_type (cur_fd, ax, sh->index, &bitsize, bigend, | 
|  | name)); | 
|  | FIELD_BITSIZE (*f) = bitsize; | 
|  | } | 
|  | break; | 
|  |  | 
|  | case stIndirect:		/* forward declaration on Irix5 */ | 
|  | /* Forward declarations from Irix5 cc are handled by cross_ref, | 
|  | skip them.  */ | 
|  | break; | 
|  |  | 
|  | case stTypedef:		/* type definition */ | 
|  | found_ecoff_debugging_info = 1; | 
|  |  | 
|  | /* Typedefs for forward declarations and opaque structs from alpha cc | 
|  | are handled by cross_ref, skip them.  */ | 
|  | if (sh->iss == 0) | 
|  | break; | 
|  |  | 
|  | /* Parse the type or use the pending type.  */ | 
|  | pend = is_pending_symbol (cur_fdr, ext_sh); | 
|  | if (pend == NULL) | 
|  | { | 
|  | t = parse_type (cur_fd, ax, sh->index, NULL, bigend, name); | 
|  | add_pending (cur_fdr, ext_sh, t); | 
|  | } | 
|  | else | 
|  | t = pend->t; | 
|  |  | 
|  | /* Mips cc puts out a typedef with the name of the struct for forward | 
|  | declarations.  These should not go into the symbol table and | 
|  | TYPE_NAME should not be set for them. | 
|  | They can't be distinguished from an intentional typedef to | 
|  | the same name however: | 
|  | x.h: | 
|  | struct x { int ix; int jx; }; | 
|  | struct xx; | 
|  | x.c: | 
|  | typedef struct x x; | 
|  | struct xx {int ixx; int jxx; }; | 
|  | generates a cross referencing stTypedef for x and xx. | 
|  | The user visible effect of this is that the type of a pointer | 
|  | to struct foo sometimes is given as `foo *' instead of `struct foo *'. | 
|  | The problem is fixed with alpha cc and Irix5 cc.  */ | 
|  |  | 
|  | /* However if the typedef cross references to an opaque aggregate, it | 
|  | is safe to omit it from the symbol table.  */ | 
|  |  | 
|  | if (has_opaque_xref (cur_fdr, sh)) | 
|  | break; | 
|  | s = new_symbol (name); | 
|  | s->set_domain (VAR_DOMAIN); | 
|  | s->set_aclass_index (LOC_TYPEDEF); | 
|  | s->set_value_block (top_stack->cur_block); | 
|  | s->set_type (t); | 
|  | add_symbol (s, top_stack->cur_st, top_stack->cur_block); | 
|  |  | 
|  | /* Incomplete definitions of structs should not get a name.  */ | 
|  | if (s->type ()->name () == NULL | 
|  | && (s->type ()->num_fields () != 0 | 
|  | || (s->type ()->code () != TYPE_CODE_STRUCT | 
|  | && s->type ()->code () != TYPE_CODE_UNION))) | 
|  | { | 
|  | if (s->type ()->code () == TYPE_CODE_PTR | 
|  | || s->type ()->code () == TYPE_CODE_FUNC) | 
|  | { | 
|  | /* If we are giving a name to a type such as "pointer to | 
|  | foo" or "function returning foo", we better not set | 
|  | the TYPE_NAME.  If the program contains "typedef char | 
|  | *caddr_t;", we don't want all variables of type char | 
|  | * to print as caddr_t.  This is not just a | 
|  | consequence of GDB's type management; CC and GCC (at | 
|  | least through version 2.4) both output variables of | 
|  | either type char * or caddr_t with the type | 
|  | refering to the stTypedef symbol for caddr_t.  If a future | 
|  | compiler cleans this up it GDB is not ready for it | 
|  | yet, but if it becomes ready we somehow need to | 
|  | disable this check (without breaking the PCC/GCC2.4 | 
|  | case). | 
|  |  | 
|  | Sigh. | 
|  |  | 
|  | Fortunately, this check seems not to be necessary | 
|  | for anything except pointers or functions.  */ | 
|  | } | 
|  | else | 
|  | s->type ()->set_name (s->linkage_name ()); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case stFile:		/* file name */ | 
|  | push_parse_stack (); | 
|  | top_stack->blocktype = sh->st; | 
|  | break; | 
|  |  | 
|  | /* I`ve never seen these for C */ | 
|  | case stRegReloc: | 
|  | break;			/* register relocation */ | 
|  | case stForward: | 
|  | break;			/* forwarding address */ | 
|  | case stConstant: | 
|  | break;			/* constant */ | 
|  | default: | 
|  | complaint (_("unknown symbol type 0x%x"), sh->st); | 
|  | break; | 
|  | } | 
|  |  | 
|  | return count; | 
|  | } | 
|  |  | 
|  | /* Basic types.  */ | 
|  |  | 
|  | static const struct objfile_key<struct type *, | 
|  | gdb::noop_deleter<struct type *>> | 
|  | basic_type_data; | 
|  |  | 
|  | static struct type * | 
|  | basic_type (int bt, struct objfile *objfile) | 
|  | { | 
|  | struct gdbarch *gdbarch = objfile->arch (); | 
|  | struct type **map_bt = basic_type_data.get (objfile); | 
|  | struct type *tp; | 
|  |  | 
|  | if (bt >= btMax) | 
|  | return NULL; | 
|  |  | 
|  | if (!map_bt) | 
|  | { | 
|  | map_bt = OBSTACK_CALLOC (&objfile->objfile_obstack, | 
|  | btMax, struct type *); | 
|  | basic_type_data.set (objfile, map_bt); | 
|  | } | 
|  |  | 
|  | if (map_bt[bt]) | 
|  | return map_bt[bt]; | 
|  |  | 
|  | switch (bt) | 
|  | { | 
|  | case btNil: | 
|  | tp = objfile_type (objfile)->builtin_void; | 
|  | break; | 
|  |  | 
|  | case btAdr: | 
|  | tp = init_pointer_type (objfile, 32, "adr_32", | 
|  | objfile_type (objfile)->builtin_void); | 
|  | break; | 
|  |  | 
|  | case btChar: | 
|  | tp = init_integer_type (objfile, 8, 0, "char"); | 
|  | tp->set_has_no_signedness (true); | 
|  | break; | 
|  |  | 
|  | case btUChar: | 
|  | tp = init_integer_type (objfile, 8, 1, "unsigned char"); | 
|  | break; | 
|  |  | 
|  | case btShort: | 
|  | tp = init_integer_type (objfile, 16, 0, "short"); | 
|  | break; | 
|  |  | 
|  | case btUShort: | 
|  | tp = init_integer_type (objfile, 16, 1, "unsigned short"); | 
|  | break; | 
|  |  | 
|  | case btInt: | 
|  | tp = init_integer_type (objfile, 32, 0, "int"); | 
|  | break; | 
|  |  | 
|  | case btUInt: | 
|  | tp = init_integer_type (objfile, 32, 1, "unsigned int"); | 
|  | break; | 
|  |  | 
|  | case btLong: | 
|  | tp = init_integer_type (objfile, 32, 0, "long"); | 
|  | break; | 
|  |  | 
|  | case btULong: | 
|  | tp = init_integer_type (objfile, 32, 1, "unsigned long"); | 
|  | break; | 
|  |  | 
|  | case btFloat: | 
|  | tp = init_float_type (objfile, gdbarch_float_bit (gdbarch), | 
|  | "float", gdbarch_float_format (gdbarch)); | 
|  | break; | 
|  |  | 
|  | case btDouble: | 
|  | tp = init_float_type (objfile, gdbarch_double_bit (gdbarch), | 
|  | "double", gdbarch_double_format (gdbarch)); | 
|  | break; | 
|  |  | 
|  | case btComplex: | 
|  | tp = init_complex_type ("complex", basic_type (btFloat, objfile)); | 
|  | break; | 
|  |  | 
|  | case btDComplex: | 
|  | tp = init_complex_type ("double complex", basic_type (btFloat, objfile)); | 
|  | break; | 
|  |  | 
|  | case btFixedDec: | 
|  | /* We use TYPE_CODE_INT to print these as integers.  Does this do any | 
|  | good?  Would we be better off with TYPE_CODE_ERROR?  Should | 
|  | TYPE_CODE_ERROR print things in hex if it knows the size?  */ | 
|  | tp = init_integer_type (objfile, gdbarch_int_bit (gdbarch), 0, | 
|  | "fixed decimal"); | 
|  | break; | 
|  |  | 
|  | case btFloatDec: | 
|  | tp = init_type (objfile, TYPE_CODE_ERROR, | 
|  | gdbarch_double_bit (gdbarch), "floating decimal"); | 
|  | break; | 
|  |  | 
|  | case btString: | 
|  | /* Is a "string" the way btString means it the same as TYPE_CODE_STRING? | 
|  | FIXME.  */ | 
|  | tp = init_type (objfile, TYPE_CODE_STRING, TARGET_CHAR_BIT, "string"); | 
|  | break; | 
|  |  | 
|  | case btVoid: | 
|  | tp = objfile_type (objfile)->builtin_void; | 
|  | break; | 
|  |  | 
|  | case btLong64: | 
|  | tp = init_integer_type (objfile, 64, 0, "long"); | 
|  | break; | 
|  |  | 
|  | case btULong64: | 
|  | tp = init_integer_type (objfile, 64, 1, "unsigned long"); | 
|  | break; | 
|  |  | 
|  | case btLongLong64: | 
|  | tp = init_integer_type (objfile, 64, 0, "long long"); | 
|  | break; | 
|  |  | 
|  | case btULongLong64: | 
|  | tp = init_integer_type (objfile, 64, 1, "unsigned long long"); | 
|  | break; | 
|  |  | 
|  | case btAdr64: | 
|  | tp = init_pointer_type (objfile, 64, "adr_64", | 
|  | objfile_type (objfile)->builtin_void); | 
|  | break; | 
|  |  | 
|  | case btInt64: | 
|  | tp = init_integer_type (objfile, 64, 0, "int"); | 
|  | break; | 
|  |  | 
|  | case btUInt64: | 
|  | tp = init_integer_type (objfile, 64, 1, "unsigned int"); | 
|  | break; | 
|  |  | 
|  | default: | 
|  | tp = NULL; | 
|  | break; | 
|  | } | 
|  |  | 
|  | map_bt[bt] = tp; | 
|  | return tp; | 
|  | } | 
|  |  | 
|  | /* Parse the type information provided in the raw AX entries for | 
|  | the symbol SH.  Return the bitfield size in BS, in case. | 
|  | We must byte-swap the AX entries before we use them; BIGEND says whether | 
|  | they are big-endian or little-endian (from fh->fBigendian).  */ | 
|  |  | 
|  | static struct type * | 
|  | parse_type (int fd, union aux_ext *ax, unsigned int aux_index, int *bs, | 
|  | int bigend, const char *sym_name) | 
|  | { | 
|  | TIR t[1]; | 
|  | struct type *tp = 0; | 
|  | enum type_code type_code = TYPE_CODE_UNDEF; | 
|  |  | 
|  | /* Handle undefined types, they have indexNil.  */ | 
|  | if (aux_index == indexNil) | 
|  | return basic_type (btInt, mdebugread_objfile); | 
|  |  | 
|  | /* Handle corrupt aux indices.  */ | 
|  | if (aux_index >= (debug_info->fdr + fd)->caux) | 
|  | { | 
|  | index_complaint (sym_name); | 
|  | return basic_type (btInt, mdebugread_objfile); | 
|  | } | 
|  | ax += aux_index; | 
|  |  | 
|  | /* Use aux as a type information record, map its basic type.  */ | 
|  | (*debug_swap->swap_tir_in) (bigend, &ax->a_ti, t); | 
|  | tp = basic_type (t->bt, mdebugread_objfile); | 
|  | if (tp == NULL) | 
|  | { | 
|  | /* Cannot use builtin types -- build our own.  */ | 
|  | switch (t->bt) | 
|  | { | 
|  | case btStruct: | 
|  | type_code = TYPE_CODE_STRUCT; | 
|  | break; | 
|  | case btUnion: | 
|  | type_code = TYPE_CODE_UNION; | 
|  | break; | 
|  | case btEnum: | 
|  | type_code = TYPE_CODE_ENUM; | 
|  | break; | 
|  | case btRange: | 
|  | type_code = TYPE_CODE_RANGE; | 
|  | break; | 
|  | case btSet: | 
|  | type_code = TYPE_CODE_SET; | 
|  | break; | 
|  | case btIndirect: | 
|  | /* alpha cc -migrate uses this for typedefs.  The true type will | 
|  | be obtained by crossreferencing below.  */ | 
|  | type_code = TYPE_CODE_ERROR; | 
|  | break; | 
|  | case btTypedef: | 
|  | /* alpha cc uses this for typedefs.  The true type will be | 
|  | obtained by crossreferencing below.  */ | 
|  | type_code = TYPE_CODE_ERROR; | 
|  | break; | 
|  | default: | 
|  | basic_type_complaint (t->bt, sym_name); | 
|  | return basic_type (btInt, mdebugread_objfile); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Move on to next aux.  */ | 
|  | ax++; | 
|  |  | 
|  | if (t->fBitfield) | 
|  | { | 
|  | int width = AUX_GET_WIDTH (bigend, ax); | 
|  |  | 
|  | /* Inhibit core dumps if TIR is corrupted.  */ | 
|  | if (bs == NULL) | 
|  | { | 
|  | /* Alpha cc -migrate encodes char and unsigned char types | 
|  | as short and unsigned short types with a field width of 8. | 
|  | Enum types also have a field width which we ignore for now.  */ | 
|  | if (t->bt == btShort && width == 8) | 
|  | tp = basic_type (btChar, mdebugread_objfile); | 
|  | else if (t->bt == btUShort && width == 8) | 
|  | tp = basic_type (btUChar, mdebugread_objfile); | 
|  | else if (t->bt == btEnum) | 
|  | ; | 
|  | else | 
|  | complaint (_("can't handle TIR fBitfield for %s"), | 
|  | sym_name); | 
|  | } | 
|  | else | 
|  | *bs = width; | 
|  | ax++; | 
|  | } | 
|  |  | 
|  | /* A btIndirect entry cross references to an aux entry containing | 
|  | the type.  */ | 
|  | if (t->bt == btIndirect) | 
|  | { | 
|  | RNDXR rn[1]; | 
|  | int rf; | 
|  | FDR *xref_fh; | 
|  | int xref_fd; | 
|  |  | 
|  | (*debug_swap->swap_rndx_in) (bigend, &ax->a_rndx, rn); | 
|  | ax++; | 
|  | if (rn->rfd == 0xfff) | 
|  | { | 
|  | rf = AUX_GET_ISYM (bigend, ax); | 
|  | ax++; | 
|  | } | 
|  | else | 
|  | rf = rn->rfd; | 
|  |  | 
|  | if (rf == -1) | 
|  | { | 
|  | complaint (_("unable to cross ref btIndirect for %s"), sym_name); | 
|  | return basic_type (btInt, mdebugread_objfile); | 
|  | } | 
|  | xref_fh = get_rfd (fd, rf); | 
|  | xref_fd = xref_fh - debug_info->fdr; | 
|  | tp = parse_type (xref_fd, debug_info->external_aux + xref_fh->iauxBase, | 
|  | rn->index, NULL, xref_fh->fBigendian, sym_name); | 
|  | } | 
|  |  | 
|  | /* All these types really point to some (common) MIPS type | 
|  | definition, and only the type-qualifiers fully identify | 
|  | them.  We'll make the same effort at sharing.  */ | 
|  | if (t->bt == btStruct || | 
|  | t->bt == btUnion || | 
|  | t->bt == btEnum || | 
|  |  | 
|  | /* btSet (I think) implies that the name is a tag name, not a typedef | 
|  | name.  This apparently is a MIPS extension for C sets.  */ | 
|  | t->bt == btSet) | 
|  | { | 
|  | const char *name; | 
|  |  | 
|  | /* Try to cross reference this type, build new type on failure.  */ | 
|  | ax += cross_ref (fd, ax, &tp, type_code, &name, bigend, sym_name); | 
|  | if (tp == NULL) | 
|  | tp = init_type (mdebugread_objfile, type_code, 0, NULL); | 
|  |  | 
|  | /* DEC c89 produces cross references to qualified aggregate types, | 
|  | dereference them.  */ | 
|  | while (tp->code () == TYPE_CODE_PTR | 
|  | || tp->code () == TYPE_CODE_ARRAY) | 
|  | tp = TYPE_TARGET_TYPE (tp); | 
|  |  | 
|  | /* Make sure that TYPE_CODE(tp) has an expected type code. | 
|  | Any type may be returned from cross_ref if file indirect entries | 
|  | are corrupted.  */ | 
|  | if (tp->code () != TYPE_CODE_STRUCT | 
|  | && tp->code () != TYPE_CODE_UNION | 
|  | && tp->code () != TYPE_CODE_ENUM) | 
|  | { | 
|  | unexpected_type_code_complaint (sym_name); | 
|  | } | 
|  | else | 
|  | { | 
|  | /* Usually, TYPE_CODE(tp) is already type_code.  The main | 
|  | exception is if we guessed wrong re struct/union/enum. | 
|  | But for struct vs. union a wrong guess is harmless, so | 
|  | don't complain().  */ | 
|  | if ((tp->code () == TYPE_CODE_ENUM | 
|  | && type_code != TYPE_CODE_ENUM) | 
|  | || (tp->code () != TYPE_CODE_ENUM | 
|  | && type_code == TYPE_CODE_ENUM)) | 
|  | { | 
|  | bad_tag_guess_complaint (sym_name); | 
|  | } | 
|  |  | 
|  | if (tp->code () != type_code) | 
|  | { | 
|  | tp->set_code (type_code); | 
|  | } | 
|  |  | 
|  | /* Do not set the tag name if it is a compiler generated tag name | 
|  | (.Fxx or .xxfake or empty) for unnamed struct/union/enums.  */ | 
|  | if (name[0] == '.' || name[0] == '\0') | 
|  | tp->set_name (NULL); | 
|  | else if (tp->name () == NULL | 
|  | || strcmp (tp->name (), name) != 0) | 
|  | tp->set_name (obstack_strdup (&mdebugread_objfile->objfile_obstack, | 
|  | name)); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* All these types really point to some (common) MIPS type | 
|  | definition, and only the type-qualifiers fully identify | 
|  | them.  We'll make the same effort at sharing. | 
|  | FIXME: We are not doing any guessing on range types.  */ | 
|  | if (t->bt == btRange) | 
|  | { | 
|  | const char *name; | 
|  |  | 
|  | /* Try to cross reference this type, build new type on failure.  */ | 
|  | ax += cross_ref (fd, ax, &tp, type_code, &name, bigend, sym_name); | 
|  | if (tp == NULL) | 
|  | tp = init_type (mdebugread_objfile, type_code, 0, NULL); | 
|  |  | 
|  | /* Make sure that TYPE_CODE(tp) has an expected type code. | 
|  | Any type may be returned from cross_ref if file indirect entries | 
|  | are corrupted.  */ | 
|  | if (tp->code () != TYPE_CODE_RANGE) | 
|  | { | 
|  | unexpected_type_code_complaint (sym_name); | 
|  | } | 
|  | else | 
|  | { | 
|  | /* Usually, TYPE_CODE(tp) is already type_code.  The main | 
|  | exception is if we guessed wrong re struct/union/enum.  */ | 
|  | if (tp->code () != type_code) | 
|  | { | 
|  | bad_tag_guess_complaint (sym_name); | 
|  | tp->set_code (type_code); | 
|  | } | 
|  | if (tp->name () == NULL | 
|  | || strcmp (tp->name (), name) != 0) | 
|  | tp->set_name (obstack_strdup (&mdebugread_objfile->objfile_obstack, | 
|  | name)); | 
|  | } | 
|  | } | 
|  | if (t->bt == btTypedef) | 
|  | { | 
|  | const char *name; | 
|  |  | 
|  | /* Try to cross reference this type, it should succeed.  */ | 
|  | ax += cross_ref (fd, ax, &tp, type_code, &name, bigend, sym_name); | 
|  | if (tp == NULL) | 
|  | { | 
|  | complaint (_("unable to cross ref btTypedef for %s"), sym_name); | 
|  | tp = basic_type (btInt, mdebugread_objfile); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Deal with range types.  */ | 
|  | if (t->bt == btRange) | 
|  | { | 
|  | tp->set_num_fields (0); | 
|  | tp->set_bounds (((struct range_bounds *) | 
|  | TYPE_ZALLOC (tp, sizeof (struct range_bounds)))); | 
|  | tp->bounds ()->low.set_const_val (AUX_GET_DNLOW (bigend, ax)); | 
|  | ax++; | 
|  | tp->bounds ()->high.set_const_val (AUX_GET_DNHIGH (bigend, ax)); | 
|  | ax++; | 
|  | } | 
|  |  | 
|  | /* Parse all the type qualifiers now.  If there are more | 
|  | than 6 the game will continue in the next aux.  */ | 
|  |  | 
|  | while (1) | 
|  | { | 
|  | #define PARSE_TQ(tq) \ | 
|  | if (t->tq != tqNil) \ | 
|  | ax += upgrade_type(fd, &tp, t->tq, ax, bigend, sym_name); \ | 
|  | else \ | 
|  | break; | 
|  |  | 
|  | PARSE_TQ (tq0); | 
|  | PARSE_TQ (tq1); | 
|  | PARSE_TQ (tq2); | 
|  | PARSE_TQ (tq3); | 
|  | PARSE_TQ (tq4); | 
|  | PARSE_TQ (tq5); | 
|  | #undef	PARSE_TQ | 
|  |  | 
|  | /* mips cc 2.x and gcc never put out continued aux entries.  */ | 
|  | if (!t->continued) | 
|  | break; | 
|  |  | 
|  | (*debug_swap->swap_tir_in) (bigend, &ax->a_ti, t); | 
|  | ax++; | 
|  | } | 
|  |  | 
|  | /* Complain for illegal continuations due to corrupt aux entries.  */ | 
|  | if (t->continued) | 
|  | complaint (_("illegal TIR continued for %s"), sym_name); | 
|  |  | 
|  | return tp; | 
|  | } | 
|  |  | 
|  | /* Make up a complex type from a basic one.  Type is passed by | 
|  | reference in TPP and side-effected as necessary.  The type | 
|  | qualifier TQ says how to handle the aux symbols at AX for | 
|  | the symbol SX we are currently analyzing.  BIGEND says whether | 
|  | aux symbols are big-endian or little-endian. | 
|  | Returns the number of aux symbols we parsed.  */ | 
|  |  | 
|  | static int | 
|  | upgrade_type (int fd, struct type **tpp, int tq, union aux_ext *ax, int bigend, | 
|  | const char *sym_name) | 
|  | { | 
|  | int off; | 
|  | struct type *t; | 
|  |  | 
|  | /* Used in array processing.  */ | 
|  | int rf, id; | 
|  | FDR *fh; | 
|  | struct type *range; | 
|  | struct type *indx; | 
|  | int lower, upper; | 
|  | RNDXR rndx; | 
|  |  | 
|  | switch (tq) | 
|  | { | 
|  | case tqPtr: | 
|  | t = lookup_pointer_type (*tpp); | 
|  | *tpp = t; | 
|  | return 0; | 
|  |  | 
|  | case tqProc: | 
|  | t = lookup_function_type (*tpp); | 
|  | *tpp = t; | 
|  | return 0; | 
|  |  | 
|  | case tqArray: | 
|  | off = 0; | 
|  |  | 
|  | /* Determine and record the domain type (type of index).  */ | 
|  | (*debug_swap->swap_rndx_in) (bigend, &ax->a_rndx, &rndx); | 
|  | id = rndx.index; | 
|  | rf = rndx.rfd; | 
|  | if (rf == 0xfff) | 
|  | { | 
|  | ax++; | 
|  | rf = AUX_GET_ISYM (bigend, ax); | 
|  | off++; | 
|  | } | 
|  | fh = get_rfd (fd, rf); | 
|  |  | 
|  | indx = parse_type (fh - debug_info->fdr, | 
|  | debug_info->external_aux + fh->iauxBase, | 
|  | id, NULL, bigend, sym_name); | 
|  |  | 
|  | /* The bounds type should be an integer type, but might be anything | 
|  | else due to corrupt aux entries.  */ | 
|  | if (indx->code () != TYPE_CODE_INT) | 
|  | { | 
|  | complaint (_("illegal array index type for %s, assuming int"), | 
|  | sym_name); | 
|  | indx = objfile_type (mdebugread_objfile)->builtin_int; | 
|  | } | 
|  |  | 
|  | /* Get the bounds, and create the array type.  */ | 
|  | ax++; | 
|  | lower = AUX_GET_DNLOW (bigend, ax); | 
|  | ax++; | 
|  | upper = AUX_GET_DNHIGH (bigend, ax); | 
|  | ax++; | 
|  | rf = AUX_GET_WIDTH (bigend, ax);	/* bit size of array element */ | 
|  |  | 
|  | range = create_static_range_type (NULL, indx, lower, upper); | 
|  |  | 
|  | t = create_array_type (NULL, *tpp, range); | 
|  |  | 
|  | /* We used to fill in the supplied array element bitsize | 
|  | here if the TYPE_LENGTH of the target type was zero. | 
|  | This happens for a `pointer to an array of anonymous structs', | 
|  | but in this case the array element bitsize is also zero, | 
|  | so nothing is gained. | 
|  | And we used to check the TYPE_LENGTH of the target type against | 
|  | the supplied array element bitsize. | 
|  | gcc causes a mismatch for `pointer to array of object', | 
|  | since the sdb directives it uses do not have a way of | 
|  | specifying the bitsize, but it does no harm (the | 
|  | TYPE_LENGTH should be correct) and we should be able to | 
|  | ignore the erroneous bitsize from the auxiliary entry safely. | 
|  | dbx seems to ignore it too.  */ | 
|  |  | 
|  | /* TYPE_TARGET_STUB now takes care of the zero TYPE_LENGTH problem.  */ | 
|  | if (TYPE_LENGTH (*tpp) == 0) | 
|  | t->set_target_is_stub (true); | 
|  |  | 
|  | *tpp = t; | 
|  | return 4 + off; | 
|  |  | 
|  | case tqVol: | 
|  | /* Volatile -- currently ignored */ | 
|  | return 0; | 
|  |  | 
|  | case tqConst: | 
|  | /* Const -- currently ignored */ | 
|  | return 0; | 
|  |  | 
|  | default: | 
|  | complaint (_("unknown type qualifier 0x%x"), tq); | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Parse a procedure descriptor record PR.  Note that the procedure is | 
|  | parsed _after_ the local symbols, now we just insert the extra | 
|  | information we need into a MDEBUG_EFI_SYMBOL_NAME symbol that has | 
|  | already been placed in the procedure's main block.  Note also that | 
|  | images that have been partially stripped (ld -x) have been deprived | 
|  | of local symbols, and we have to cope with them here.  FIRST_OFF is | 
|  | the offset of the first procedure for this FDR; we adjust the | 
|  | address by this amount, but I don't know why.  SEARCH_SYMTAB is the symtab | 
|  | to look for the function which contains the MDEBUG_EFI_SYMBOL_NAME symbol | 
|  | in question, or NULL to use top_stack->cur_block.  */ | 
|  |  | 
|  | static void | 
|  | parse_procedure (PDR *pr, struct compunit_symtab *search_symtab, | 
|  | legacy_psymtab *pst) | 
|  | { | 
|  | struct symbol *s, *i; | 
|  | const struct block *b; | 
|  | char *sh_name; | 
|  |  | 
|  | /* Simple rule to find files linked "-x".  */ | 
|  | if (cur_fdr->rss == -1) | 
|  | { | 
|  | if (pr->isym == -1) | 
|  | { | 
|  | /* Static procedure at address pr->adr.  Sigh.  */ | 
|  | /* FIXME-32x64.  assuming pr->adr fits in long.  */ | 
|  | complaint (_("can't handle PDR for static proc at 0x%lx"), | 
|  | (unsigned long) pr->adr); | 
|  | return; | 
|  | } | 
|  | else | 
|  | { | 
|  | /* external */ | 
|  | EXTR she; | 
|  |  | 
|  | (*debug_swap->swap_ext_in) (cur_bfd, | 
|  | ((char *) debug_info->external_ext | 
|  | + (pr->isym | 
|  | * debug_swap->external_ext_size)), | 
|  | &she); | 
|  | sh_name = debug_info->ssext + she.asym.iss; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | /* Full symbols */ | 
|  | SYMR sh; | 
|  |  | 
|  | (*debug_swap->swap_sym_in) (cur_bfd, | 
|  | ((char *) debug_info->external_sym | 
|  | + ((cur_fdr->isymBase + pr->isym) | 
|  | * debug_swap->external_sym_size)), | 
|  | &sh); | 
|  | sh_name = debug_info->ss + cur_fdr->issBase + sh.iss; | 
|  | } | 
|  |  | 
|  | if (search_symtab != NULL) | 
|  | { | 
|  | #if 0 | 
|  | /* This loses both in the case mentioned (want a static, find a global), | 
|  | but also if we are looking up a non-mangled name which happens to | 
|  | match the name of a mangled function.  */ | 
|  | /* We have to save the cur_fdr across the call to lookup_symbol. | 
|  | If the pdr is for a static function and if a global function with | 
|  | the same name exists, lookup_symbol will eventually read in the symtab | 
|  | for the global function and clobber cur_fdr.  */ | 
|  | FDR *save_cur_fdr = cur_fdr; | 
|  |  | 
|  | s = lookup_symbol (sh_name, NULL, VAR_DOMAIN, 0); | 
|  | cur_fdr = save_cur_fdr; | 
|  | #else | 
|  | s = mylookup_symbol | 
|  | (sh_name, | 
|  | BLOCKVECTOR_BLOCK (search_symtab->blockvector (), | 
|  | STATIC_BLOCK), | 
|  | VAR_DOMAIN, | 
|  | LOC_BLOCK); | 
|  | #endif | 
|  | } | 
|  | else | 
|  | s = mylookup_symbol (sh_name, top_stack->cur_block, | 
|  | VAR_DOMAIN, LOC_BLOCK); | 
|  |  | 
|  | if (s != 0) | 
|  | { | 
|  | b = s->value_block (); | 
|  | } | 
|  | else | 
|  | { | 
|  | complaint (_("PDR for %s, but no symbol"), sh_name); | 
|  | #if 1 | 
|  | return; | 
|  | #else | 
|  | /* FIXME -- delete.  We can't do symbol allocation now; it's all done.  */ | 
|  | s = new_symbol (sh_name); | 
|  | s->set_domain (VAR_DOMAIN); | 
|  | SYMBOL_CLASS (s) = LOC_BLOCK; | 
|  | /* Don't know its type, hope int is ok.  */ | 
|  | s->type () | 
|  | = lookup_function_type (objfile_type (pst->objfile)->builtin_int); | 
|  | add_symbol (s, top_stack->cur_st, top_stack->cur_block); | 
|  | /* Won't have symbols for this one.  */ | 
|  | b = new_block (2); | 
|  | SYMBOL_BLOCK_VALUE (s) = b; | 
|  | BLOCK_FUNCTION (b) = s; | 
|  | BLOCK_START (b) = pr->adr; | 
|  | /* BOUND used to be the end of procedure's text, but the | 
|  | argument is no longer passed in.  */ | 
|  | BLOCK_END (b) = bound; | 
|  | BLOCK_SUPERBLOCK (b) = top_stack->cur_block; | 
|  | add_block (b, top_stack->cur_st); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | i = mylookup_symbol (MDEBUG_EFI_SYMBOL_NAME, b, LABEL_DOMAIN, LOC_CONST); | 
|  |  | 
|  | if (i) | 
|  | { | 
|  | struct mdebug_extra_func_info *e; | 
|  |  | 
|  | e = (struct mdebug_extra_func_info *) i->value_bytes (); | 
|  | e->pdr = *pr; | 
|  |  | 
|  | /* GDB expects the absolute function start address for the | 
|  | procedure descriptor in e->pdr.adr. | 
|  | As the address in the procedure descriptor is usually relative, | 
|  | we would have to relocate e->pdr.adr with cur_fdr->adr. | 
|  | Unfortunately cur_fdr->adr and e->pdr.adr are both absolute | 
|  | in shared libraries on some systems, and on other systems | 
|  | e->pdr.adr is sometimes offset by a bogus value. | 
|  | To work around these problems, we replace e->pdr.adr with | 
|  | the start address of the function.  */ | 
|  | e->pdr.adr = BLOCK_START (b); | 
|  | } | 
|  |  | 
|  | /* It would be reasonable that functions that have been compiled | 
|  | without debugging info have a btNil type for their return value, | 
|  | and functions that are void and are compiled with debugging info | 
|  | have btVoid. | 
|  | gcc and DEC f77 put out btNil types for both cases, so btNil is mapped | 
|  | to TYPE_CODE_VOID in parse_type to get the `compiled with debugging info' | 
|  | case right. | 
|  | The glevel field in cur_fdr could be used to determine the presence | 
|  | of debugging info, but GCC doesn't always pass the -g switch settings | 
|  | to the assembler and GAS doesn't set the glevel field from the -g switch | 
|  | settings. | 
|  | To work around these problems, the return value type of a TYPE_CODE_VOID | 
|  | function is adjusted accordingly if no debugging info was found in the | 
|  | compilation unit.  */ | 
|  |  | 
|  | if (processing_gcc_compilation == 0 | 
|  | && found_ecoff_debugging_info == 0 | 
|  | && TYPE_TARGET_TYPE (s->type ())->code () == TYPE_CODE_VOID) | 
|  | s->set_type (objfile_type (mdebugread_objfile)->nodebug_text_symbol); | 
|  | } | 
|  |  | 
|  | /* Parse the external symbol ES.  Just call parse_symbol() after | 
|  | making sure we know where the aux are for it. | 
|  | BIGEND says whether aux entries are big-endian or little-endian. | 
|  |  | 
|  | This routine clobbers top_stack->cur_block and ->cur_st.  */ | 
|  |  | 
|  | static void | 
|  | parse_external (EXTR *es, int bigend, const section_offsets §ion_offsets, | 
|  | struct objfile *objfile) | 
|  | { | 
|  | union aux_ext *ax; | 
|  |  | 
|  | if (es->ifd != ifdNil) | 
|  | { | 
|  | cur_fd = es->ifd; | 
|  | cur_fdr = debug_info->fdr + cur_fd; | 
|  | ax = debug_info->external_aux + cur_fdr->iauxBase; | 
|  | } | 
|  | else | 
|  | { | 
|  | cur_fdr = debug_info->fdr; | 
|  | ax = 0; | 
|  | } | 
|  |  | 
|  | /* Reading .o files */ | 
|  | if (SC_IS_UNDEF (es->asym.sc) || es->asym.sc == scNil) | 
|  | { | 
|  | const char *what; | 
|  | switch (es->asym.st) | 
|  | { | 
|  | case stNil: | 
|  | /* These are generated for static symbols in .o files, | 
|  | ignore them.  */ | 
|  | return; | 
|  | case stStaticProc: | 
|  | case stProc: | 
|  | what = "procedure"; | 
|  | n_undef_procs++; | 
|  | break; | 
|  | case stGlobal: | 
|  | what = "variable"; | 
|  | n_undef_vars++; | 
|  | break; | 
|  | case stLabel: | 
|  | what = "label"; | 
|  | n_undef_labels++; | 
|  | break; | 
|  | default: | 
|  | what = "symbol"; | 
|  | break; | 
|  | } | 
|  | n_undef_symbols++; | 
|  | /* FIXME:  Turn this into a complaint?  */ | 
|  | if (info_verbose) | 
|  | gdb_printf (_("Warning: %s `%s' is undefined (in %s)\n"), | 
|  | what, debug_info->ssext + es->asym.iss, | 
|  | fdr_name (cur_fdr)); | 
|  | return; | 
|  | } | 
|  |  | 
|  | switch (es->asym.st) | 
|  | { | 
|  | case stProc: | 
|  | case stStaticProc: | 
|  | /* There is no need to parse the external procedure symbols. | 
|  | If they are from objects compiled without -g, their index will | 
|  | be indexNil, and the symbol definition from the minimal symbol | 
|  | is preferrable (yielding a function returning int instead of int). | 
|  | If the index points to a local procedure symbol, the local | 
|  | symbol already provides the correct type. | 
|  | Note that the index of the external procedure symbol points | 
|  | to the local procedure symbol in the local symbol table, and | 
|  | _not_ to the auxiliary symbol info.  */ | 
|  | break; | 
|  | case stGlobal: | 
|  | case stLabel: | 
|  | /* Global common symbols are resolved by the runtime loader, | 
|  | ignore them.  */ | 
|  | if (SC_IS_COMMON (es->asym.sc)) | 
|  | break; | 
|  |  | 
|  | /* Note that the case of a symbol with indexNil must be handled | 
|  | anyways by parse_symbol().  */ | 
|  | parse_symbol (&es->asym, ax, NULL, | 
|  | bigend, section_offsets, objfile); | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Parse the line number info for file descriptor FH into | 
|  | GDB's linetable LT.  MIPS' encoding requires a little bit | 
|  | of magic to get things out.  Note also that MIPS' line | 
|  | numbers can go back and forth, apparently we can live | 
|  | with that and do not need to reorder our linetables.  */ | 
|  |  | 
|  | static void | 
|  | parse_lines (FDR *fh, PDR *pr, struct linetable *lt, int maxlines, | 
|  | CORE_ADDR textlow, CORE_ADDR lowest_pdr_addr) | 
|  | { | 
|  | unsigned char *base; | 
|  | int j, k; | 
|  | int delta, count, lineno = 0; | 
|  |  | 
|  | if (fh->cbLine == 0) | 
|  | return; | 
|  |  | 
|  | /* Scan by procedure descriptors.  */ | 
|  | k = 0; | 
|  | for (j = 0; j < fh->cpd; j++, pr++) | 
|  | { | 
|  | CORE_ADDR l; | 
|  | CORE_ADDR adr; | 
|  | unsigned char *halt; | 
|  |  | 
|  | /* No code for this one.  */ | 
|  | if (pr->iline == ilineNil || | 
|  | pr->lnLow == -1 || pr->lnHigh == -1) | 
|  | continue; | 
|  |  | 
|  | /* Determine start and end address of compressed line bytes for | 
|  | this procedure.  */ | 
|  | base = debug_info->line + fh->cbLineOffset; | 
|  | if (j != (fh->cpd - 1)) | 
|  | halt = base + pr[1].cbLineOffset; | 
|  | else | 
|  | halt = base + fh->cbLine; | 
|  | base += pr->cbLineOffset; | 
|  |  | 
|  | adr = textlow + pr->adr - lowest_pdr_addr; | 
|  |  | 
|  | l = adr >> 2;		/* in words */ | 
|  | for (lineno = pr->lnLow; base < halt;) | 
|  | { | 
|  | count = *base & 0x0f; | 
|  | delta = *base++ >> 4; | 
|  | if (delta >= 8) | 
|  | delta -= 16; | 
|  | if (delta == -8) | 
|  | { | 
|  | delta = (base[0] << 8) | base[1]; | 
|  | if (delta >= 0x8000) | 
|  | delta -= 0x10000; | 
|  | base += 2; | 
|  | } | 
|  | lineno += delta;	/* first delta is 0 */ | 
|  |  | 
|  | /* Complain if the line table overflows.  Could happen | 
|  | with corrupt binaries.  */ | 
|  | if (lt->nitems >= maxlines) | 
|  | { | 
|  | complaint (_("guessed size of linetable for %s incorrectly"), | 
|  | fdr_name (fh)); | 
|  | break; | 
|  | } | 
|  | k = add_line (lt, lineno, l, k); | 
|  | l += count + 1; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void | 
|  | function_outside_compilation_unit_complaint (const char *arg1) | 
|  | { | 
|  | complaint (_("function `%s' appears to be defined " | 
|  | "outside of all compilation units"), | 
|  | arg1); | 
|  | } | 
|  |  | 
|  | /* Use the STORAGE_CLASS to compute which section the given symbol | 
|  | belongs to, and then records this new minimal symbol.  */ | 
|  |  | 
|  | static void | 
|  | record_minimal_symbol (minimal_symbol_reader &reader, | 
|  | const char *name, const CORE_ADDR address, | 
|  | enum minimal_symbol_type ms_type, int storage_class, | 
|  | struct objfile *objfile) | 
|  | { | 
|  | int section; | 
|  |  | 
|  | switch (storage_class) | 
|  | { | 
|  | case scText: | 
|  | section = SECT_OFF_TEXT (objfile); | 
|  | break; | 
|  | case scData: | 
|  | section = SECT_OFF_DATA (objfile); | 
|  | break; | 
|  | case scBss: | 
|  | section = SECT_OFF_BSS (objfile); | 
|  | break; | 
|  | case scSData: | 
|  | section = get_section_index (objfile, ".sdata"); | 
|  | break; | 
|  | case scSBss: | 
|  | section = get_section_index (objfile, ".sbss"); | 
|  | break; | 
|  | case scRData: | 
|  | section = get_section_index (objfile, ".rdata"); | 
|  | break; | 
|  | case scInit: | 
|  | section = get_section_index (objfile, ".init"); | 
|  | break; | 
|  | case scXData: | 
|  | section = get_section_index (objfile, ".xdata"); | 
|  | break; | 
|  | case scPData: | 
|  | section = get_section_index (objfile, ".pdata"); | 
|  | break; | 
|  | case scFini: | 
|  | section = get_section_index (objfile, ".fini"); | 
|  | break; | 
|  | case scRConst: | 
|  | section = get_section_index (objfile, ".rconst"); | 
|  | break; | 
|  | #ifdef scTlsData | 
|  | case scTlsData: | 
|  | section = get_section_index (objfile, ".tlsdata"); | 
|  | break; | 
|  | #endif | 
|  | #ifdef scTlsBss | 
|  | case scTlsBss: | 
|  | section = get_section_index (objfile, ".tlsbss"); | 
|  | break; | 
|  | #endif | 
|  | default: | 
|  | /* This kind of symbol is not associated to a section.  */ | 
|  | section = -1; | 
|  | } | 
|  |  | 
|  | reader.record_with_info (name, address, ms_type, section); | 
|  | } | 
|  |  | 
|  | /* Master parsing procedure for first-pass reading of file symbols | 
|  | into a partial_symtab.  */ | 
|  |  | 
|  | static void | 
|  | parse_partial_symbols (minimal_symbol_reader &reader, | 
|  | psymtab_storage *partial_symtabs, | 
|  | struct objfile *objfile) | 
|  | { | 
|  | struct gdbarch *gdbarch = objfile->arch (); | 
|  | const bfd_size_type external_sym_size = debug_swap->external_sym_size; | 
|  | const bfd_size_type external_rfd_size = debug_swap->external_rfd_size; | 
|  | const bfd_size_type external_ext_size = debug_swap->external_ext_size; | 
|  | void (*const swap_ext_in) (bfd *, void *, EXTR *) = debug_swap->swap_ext_in; | 
|  | void (*const swap_sym_in) (bfd *, void *, SYMR *) = debug_swap->swap_sym_in; | 
|  | void (*const swap_rfd_in) (bfd *, void *, RFDT *) = debug_swap->swap_rfd_in; | 
|  | int f_idx, s_idx; | 
|  | HDRR *hdr = &debug_info->symbolic_header; | 
|  | /* Running pointers */ | 
|  | FDR *fh; | 
|  | char *ext_out; | 
|  | char *ext_out_end; | 
|  | EXTR *ext_in; | 
|  | EXTR *ext_in_end; | 
|  | SYMR sh; | 
|  | legacy_psymtab *pst; | 
|  | int textlow_not_set = 1; | 
|  |  | 
|  | /* List of current psymtab's include files.  */ | 
|  | const char **psymtab_include_list; | 
|  | int includes_allocated; | 
|  | int includes_used; | 
|  | EXTR *extern_tab; | 
|  | struct pst_map *fdr_to_pst; | 
|  | /* Index within current psymtab dependency list.  */ | 
|  | legacy_psymtab **dependency_list; | 
|  | int dependencies_used, dependencies_allocated; | 
|  | char *name; | 
|  | enum language prev_language; | 
|  | asection *text_sect; | 
|  | int relocatable = 0; | 
|  |  | 
|  | /* Irix 5.2 shared libraries have a fh->adr field of zero, but | 
|  | the shared libraries are prelinked at a high memory address. | 
|  | We have to adjust the start address of the object file for this case, | 
|  | by setting it to the start address of the first procedure in the file. | 
|  | But we should do no adjustments if we are debugging a .o file, where | 
|  | the text section (and fh->adr) really starts at zero.  */ | 
|  | text_sect = bfd_get_section_by_name (cur_bfd, ".text"); | 
|  | if (text_sect != NULL | 
|  | && (bfd_section_flags (text_sect) & SEC_RELOC)) | 
|  | relocatable = 1; | 
|  |  | 
|  | extern_tab = XOBNEWVEC (&objfile->objfile_obstack, EXTR, hdr->iextMax); | 
|  |  | 
|  | includes_allocated = 30; | 
|  | includes_used = 0; | 
|  | psymtab_include_list = (const char **) alloca (includes_allocated * | 
|  | sizeof (const char *)); | 
|  | next_symbol_text_func = mdebug_next_symbol_text; | 
|  |  | 
|  | dependencies_allocated = 30; | 
|  | dependencies_used = 0; | 
|  | dependency_list = | 
|  | (legacy_psymtab **) alloca (dependencies_allocated * | 
|  | sizeof (legacy_psymtab *)); | 
|  |  | 
|  | set_last_source_file (NULL); | 
|  |  | 
|  | /* | 
|  | * Big plan: | 
|  | * | 
|  | * Only parse the Local and External symbols, and the Relative FDR. | 
|  | * Fixup enough of the loader symtab to be able to use it. | 
|  | * Allocate space only for the file's portions we need to | 
|  | * look at.  (XXX) | 
|  | */ | 
|  |  | 
|  | max_gdbinfo = 0; | 
|  | max_glevel = MIN_GLEVEL; | 
|  |  | 
|  | /* Allocate the map FDR -> PST. | 
|  | Minor hack: -O3 images might claim some global data belongs | 
|  | to FDR -1.  We`ll go along with that.  */ | 
|  | std::vector<struct pst_map> fdr_to_pst_holder (hdr->ifdMax + 1); | 
|  | fdr_to_pst = fdr_to_pst_holder.data (); | 
|  | fdr_to_pst++; | 
|  | { | 
|  | legacy_psymtab *new_pst = new_psymtab ("", partial_symtabs, objfile); | 
|  |  | 
|  | fdr_to_pst[-1].pst = new_pst; | 
|  | FDR_IDX (new_pst) = -1; | 
|  | } | 
|  |  | 
|  | /* Allocate the global pending list.  */ | 
|  | pending_list = XOBNEWVEC (&objfile->objfile_obstack, mdebug_pending *, | 
|  | hdr->ifdMax); | 
|  | memset (pending_list, 0, | 
|  | hdr->ifdMax * sizeof (struct mdebug_pending *)); | 
|  |  | 
|  | /* Pass 0 over external syms: swap them in.  */ | 
|  | gdb::def_vector<EXTR> ext_block (hdr->iextMax); | 
|  |  | 
|  | ext_out = (char *) debug_info->external_ext; | 
|  | ext_out_end = ext_out + hdr->iextMax * external_ext_size; | 
|  | ext_in = ext_block.data (); | 
|  | for (; ext_out < ext_out_end; ext_out += external_ext_size, ext_in++) | 
|  | (*swap_ext_in) (cur_bfd, ext_out, ext_in); | 
|  |  | 
|  | /* Pass 1 over external syms: Presize and partition the list.  */ | 
|  | ext_in = ext_block.data (); | 
|  | ext_in_end = ext_in + hdr->iextMax; | 
|  | for (; ext_in < ext_in_end; ext_in++) | 
|  | { | 
|  | /* See calls to complain below.  */ | 
|  | if (ext_in->ifd >= -1 | 
|  | && ext_in->ifd < hdr->ifdMax | 
|  | && ext_in->asym.iss >= 0 | 
|  | && ext_in->asym.iss < hdr->issExtMax) | 
|  | fdr_to_pst[ext_in->ifd].n_globals++; | 
|  | } | 
|  |  | 
|  | /* Pass 1.5 over files:  partition out global symbol space.  */ | 
|  | s_idx = 0; | 
|  | for (f_idx = -1; f_idx < hdr->ifdMax; f_idx++) | 
|  | { | 
|  | fdr_to_pst[f_idx].globals_offset = s_idx; | 
|  | s_idx += fdr_to_pst[f_idx].n_globals; | 
|  | fdr_to_pst[f_idx].n_globals = 0; | 
|  | } | 
|  |  | 
|  | /* ECOFF in ELF: | 
|  |  | 
|  | For ECOFF in ELF, we skip the creation of the minimal symbols. | 
|  | The ECOFF symbols should be a subset of the Elf symbols, and the | 
|  | section information of the elf symbols will be more accurate. | 
|  | FIXME!  What about Irix 5's native linker? | 
|  |  | 
|  | By default, Elf sections which don't exist in ECOFF | 
|  | get put in ECOFF's absolute section by the gnu linker. | 
|  | Since absolute sections don't get relocated, we | 
|  | end up calculating an address different from that of | 
|  | the symbol's minimal symbol (created earlier from the | 
|  | Elf symtab). | 
|  |  | 
|  | To fix this, either : | 
|  | 1) don't create the duplicate symbol | 
|  | (assumes ECOFF symtab is a subset of the ELF symtab; | 
|  | assumes no side-effects result from ignoring ECOFF symbol) | 
|  | 2) create it, only if lookup for existing symbol in ELF's minimal | 
|  | symbols fails | 
|  | (inefficient; | 
|  | assumes no side-effects result from ignoring ECOFF symbol) | 
|  | 3) create it, but lookup ELF's minimal symbol and use it's section | 
|  | during relocation, then modify "uniquify" phase to merge and | 
|  | eliminate the duplicate symbol | 
|  | (highly inefficient) | 
|  |  | 
|  | I've implemented #1 here... | 
|  | Skip the creation of the minimal symbols based on the ECOFF | 
|  | symbol table.  */ | 
|  |  | 
|  | /* Pass 2 over external syms: fill in external symbols.  */ | 
|  | ext_in = ext_block.data (); | 
|  | ext_in_end = ext_in + hdr->iextMax; | 
|  | for (; ext_in < ext_in_end; ext_in++) | 
|  | { | 
|  | enum minimal_symbol_type ms_type = mst_text; | 
|  | CORE_ADDR svalue = ext_in->asym.value; | 
|  |  | 
|  | /* The Irix 5 native tools seem to sometimes generate bogus | 
|  | external symbols.  */ | 
|  | if (ext_in->ifd < -1 || ext_in->ifd >= hdr->ifdMax) | 
|  | { | 
|  | complaint (_("bad ifd for external symbol: %d (max %ld)"), | 
|  | ext_in->ifd, hdr->ifdMax); | 
|  | continue; | 
|  | } | 
|  | if (ext_in->asym.iss < 0 || ext_in->asym.iss >= hdr->issExtMax) | 
|  | { | 
|  | complaint (_("bad iss for external symbol: %ld (max %ld)"), | 
|  | ext_in->asym.iss, hdr->issExtMax); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | extern_tab[fdr_to_pst[ext_in->ifd].globals_offset | 
|  | + fdr_to_pst[ext_in->ifd].n_globals++] = *ext_in; | 
|  |  | 
|  |  | 
|  | if (SC_IS_UNDEF (ext_in->asym.sc) || ext_in->asym.sc == scNil) | 
|  | continue; | 
|  |  | 
|  |  | 
|  | /* Pass 3 over files, over local syms: fill in static symbols.  */ | 
|  | name = debug_info->ssext + ext_in->asym.iss; | 
|  |  | 
|  | /* Process ECOFF Symbol Types and Storage Classes.  */ | 
|  | switch (ext_in->asym.st) | 
|  | { | 
|  | case stProc: | 
|  | /* Beginnning of Procedure */ | 
|  | break; | 
|  | case stStaticProc: | 
|  | /* Load time only static procs */ | 
|  | ms_type = mst_file_text; | 
|  | break; | 
|  | case stGlobal: | 
|  | /* External symbol */ | 
|  | if (SC_IS_COMMON (ext_in->asym.sc)) | 
|  | { | 
|  | /* The value of a common symbol is its size, not its address. | 
|  | Ignore it.  */ | 
|  | continue; | 
|  | } | 
|  | else if (SC_IS_DATA (ext_in->asym.sc)) | 
|  | { | 
|  | ms_type = mst_data; | 
|  | } | 
|  | else if (SC_IS_BSS (ext_in->asym.sc)) | 
|  | { | 
|  | ms_type = mst_bss; | 
|  | } | 
|  | else if (SC_IS_SBSS (ext_in->asym.sc)) | 
|  | { | 
|  | ms_type = mst_bss; | 
|  | } | 
|  | else | 
|  | ms_type = mst_abs; | 
|  | break; | 
|  | case stLabel: | 
|  | /* Label */ | 
|  |  | 
|  | /* On certain platforms, some extra label symbols can be | 
|  | generated by the linker.  One possible usage for this kind | 
|  | of symbols is to represent the address of the begining of a | 
|  | given section.  For instance, on Tru64 5.1, the address of | 
|  | the _ftext label is the start address of the .text section. | 
|  |  | 
|  | The storage class of these symbols is usually directly | 
|  | related to the section to which the symbol refers.  For | 
|  | instance, on Tru64 5.1, the storage class for the _fdata | 
|  | label is scData, refering to the .data section. | 
|  |  | 
|  | It is actually possible that the section associated to the | 
|  | storage class of the label does not exist.  On True64 5.1 | 
|  | for instance, the libm.so shared library does not contain | 
|  | any .data section, although it contains a _fpdata label | 
|  | which storage class is scData...  Since these symbols are | 
|  | usually useless for the debugger user anyway, we just | 
|  | discard these symbols.  */ | 
|  |  | 
|  | if (SC_IS_TEXT (ext_in->asym.sc)) | 
|  | { | 
|  | if (objfile->sect_index_text == -1) | 
|  | continue; | 
|  |  | 
|  | ms_type = mst_file_text; | 
|  | } | 
|  | else if (SC_IS_DATA (ext_in->asym.sc)) | 
|  | { | 
|  | if (objfile->sect_index_data == -1) | 
|  | continue; | 
|  |  | 
|  | ms_type = mst_file_data; | 
|  | } | 
|  | else if (SC_IS_BSS (ext_in->asym.sc)) | 
|  | { | 
|  | if (objfile->sect_index_bss == -1) | 
|  | continue; | 
|  |  | 
|  | ms_type = mst_file_bss; | 
|  | } | 
|  | else if (SC_IS_SBSS (ext_in->asym.sc)) | 
|  | { | 
|  | const int sbss_sect_index = get_section_index (objfile, ".sbss"); | 
|  |  | 
|  | if (sbss_sect_index == -1) | 
|  | continue; | 
|  |  | 
|  | ms_type = mst_file_bss; | 
|  | } | 
|  | else | 
|  | ms_type = mst_abs; | 
|  | break; | 
|  | case stLocal: | 
|  | case stNil: | 
|  | /* The alpha has the section start addresses in stLocal symbols | 
|  | whose name starts with a `.'.  Skip those but complain for all | 
|  | other stLocal symbols. | 
|  | Irix6 puts the section start addresses in stNil symbols, skip | 
|  | those too.  */ | 
|  | if (name[0] == '.') | 
|  | continue; | 
|  | /* Fall through.  */ | 
|  | default: | 
|  | ms_type = mst_unknown; | 
|  | unknown_ext_complaint (name); | 
|  | } | 
|  | if (!ECOFF_IN_ELF (cur_bfd)) | 
|  | record_minimal_symbol (reader, name, svalue, ms_type, ext_in->asym.sc, | 
|  | objfile); | 
|  | } | 
|  |  | 
|  | /* Pass 3 over files, over local syms: fill in static symbols.  */ | 
|  | for (f_idx = 0; f_idx < hdr->ifdMax; f_idx++) | 
|  | { | 
|  | legacy_psymtab *save_pst; | 
|  | EXTR *ext_ptr; | 
|  | CORE_ADDR textlow; | 
|  |  | 
|  | cur_fdr = fh = debug_info->fdr + f_idx; | 
|  |  | 
|  | if (fh->csym == 0) | 
|  | { | 
|  | fdr_to_pst[f_idx].pst = NULL; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | /* Determine the start address for this object file from the | 
|  | file header and relocate it, except for Irix 5.2 zero fh->adr.  */ | 
|  | if (fh->cpd) | 
|  | textlow = fh->adr; | 
|  | else | 
|  | textlow = 0; | 
|  | pst = new legacy_psymtab (fdr_name (fh), partial_symtabs, | 
|  | objfile->per_bfd, textlow); | 
|  | pst->read_symtab_private = XOBNEW (&objfile->objfile_obstack, symloc); | 
|  | memset (pst->read_symtab_private, 0, sizeof (struct symloc)); | 
|  |  | 
|  | save_pst = pst; | 
|  | FDR_IDX (pst) = f_idx; | 
|  | CUR_BFD (pst) = cur_bfd; | 
|  | DEBUG_SWAP (pst) = debug_swap; | 
|  | DEBUG_INFO (pst) = debug_info; | 
|  | PENDING_LIST (pst) = pending_list; | 
|  |  | 
|  | /* The way to turn this into a symtab is to call...  */ | 
|  | pst->legacy_read_symtab = mdebug_read_symtab; | 
|  | pst->legacy_expand_psymtab = mdebug_expand_psymtab; | 
|  |  | 
|  | /* Set up language for the pst. | 
|  | The language from the FDR is used if it is unambigious (e.g. cfront | 
|  | with native cc and g++ will set the language to C). | 
|  | Otherwise we have to deduce the language from the filename. | 
|  | Native ecoff has every header file in a separate FDR, so | 
|  | deduce_language_from_filename will return language_unknown for | 
|  | a header file, which is not what we want. | 
|  | But the FDRs for the header files are after the FDR for the source | 
|  | file, so we can assign the language of the source file to the | 
|  | following header files.  Then we save the language in the private | 
|  | pst data so that we can reuse it when building symtabs.  */ | 
|  | prev_language = psymtab_language; | 
|  |  | 
|  | switch (fh->lang) | 
|  | { | 
|  | case langCplusplusV2: | 
|  | psymtab_language = language_cplus; | 
|  | break; | 
|  | default: | 
|  | psymtab_language = deduce_language_from_filename (fdr_name (fh)); | 
|  | break; | 
|  | } | 
|  | if (psymtab_language == language_unknown) | 
|  | psymtab_language = prev_language; | 
|  | PST_PRIVATE (pst)->pst_language = psymtab_language; | 
|  |  | 
|  | pst->set_text_high (pst->raw_text_low ()); | 
|  |  | 
|  | /* For stabs-in-ecoff files, the second symbol must be @stab. | 
|  | This symbol is emitted by mips-tfile to signal that the | 
|  | current object file uses encapsulated stabs instead of mips | 
|  | ecoff for local symbols.  (It is the second symbol because | 
|  | the first symbol is the stFile used to signal the start of a | 
|  | file).  */ | 
|  | processing_gcc_compilation = 0; | 
|  | if (fh->csym >= 2) | 
|  | { | 
|  | (*swap_sym_in) (cur_bfd, | 
|  | ((char *) debug_info->external_sym | 
|  | + (fh->isymBase + 1) * external_sym_size), | 
|  | &sh); | 
|  | if (strcmp (debug_info->ss + fh->issBase + sh.iss, | 
|  | stabs_symbol) == 0) | 
|  | processing_gcc_compilation = 2; | 
|  | } | 
|  |  | 
|  | if (processing_gcc_compilation != 0) | 
|  | { | 
|  | for (cur_sdx = 2; cur_sdx < fh->csym; cur_sdx++) | 
|  | { | 
|  | int type_code; | 
|  | const char *namestring; | 
|  |  | 
|  | (*swap_sym_in) (cur_bfd, | 
|  | (((char *) debug_info->external_sym) | 
|  | + (fh->isymBase + cur_sdx) * external_sym_size), | 
|  | &sh); | 
|  | type_code = ECOFF_UNMARK_STAB (sh.index); | 
|  | if (!ECOFF_IS_STAB (&sh)) | 
|  | { | 
|  | if (sh.st == stProc || sh.st == stStaticProc) | 
|  | { | 
|  | CORE_ADDR procaddr; | 
|  | long isym; | 
|  |  | 
|  | if (sh.st == stStaticProc) | 
|  | { | 
|  | namestring = debug_info->ss + fh->issBase + sh.iss; | 
|  | record_minimal_symbol (reader, namestring, sh.value, | 
|  | mst_file_text, sh.sc, | 
|  | objfile); | 
|  | } | 
|  | procaddr = sh.value; | 
|  |  | 
|  | isym = AUX_GET_ISYM (fh->fBigendian, | 
|  | (debug_info->external_aux | 
|  | + fh->iauxBase | 
|  | + sh.index)); | 
|  | (*swap_sym_in) (cur_bfd, | 
|  | ((char *) debug_info->external_sym | 
|  | + ((fh->isymBase + isym - 1) | 
|  | * external_sym_size)), | 
|  | &sh); | 
|  | if (sh.st == stEnd) | 
|  | { | 
|  | CORE_ADDR high = procaddr + sh.value; | 
|  |  | 
|  | /* Kludge for Irix 5.2 zero fh->adr.  */ | 
|  | if (!relocatable | 
|  | && (!pst->text_low_valid | 
|  | || procaddr < pst->raw_text_low ())) | 
|  | pst->set_text_low (procaddr); | 
|  | if (high > pst->raw_text_high ()) | 
|  | pst->set_text_high (high); | 
|  | } | 
|  | } | 
|  | else if (sh.st == stStatic) | 
|  | { | 
|  | switch (sh.sc) | 
|  | { | 
|  | case scUndefined: | 
|  | case scSUndefined: | 
|  | case scNil: | 
|  | case scAbs: | 
|  | break; | 
|  |  | 
|  | case scData: | 
|  | case scSData: | 
|  | case scRData: | 
|  | case scPData: | 
|  | case scXData: | 
|  | namestring = debug_info->ss + fh->issBase + sh.iss; | 
|  | record_minimal_symbol (reader, namestring, sh.value, | 
|  | mst_file_data, sh.sc, | 
|  | objfile); | 
|  | break; | 
|  |  | 
|  | default: | 
|  | /* FIXME!  Shouldn't this use cases for bss, | 
|  | then have the default be abs?  */ | 
|  | namestring = debug_info->ss + fh->issBase + sh.iss; | 
|  | record_minimal_symbol (reader, namestring, sh.value, | 
|  | mst_file_bss, sh.sc, | 
|  | objfile); | 
|  | break; | 
|  | } | 
|  | } | 
|  | continue; | 
|  | } | 
|  | /* Handle stabs continuation.  */ | 
|  | { | 
|  | char *stabstring = debug_info->ss + fh->issBase + sh.iss; | 
|  | /* If we need to heap-allocate STABSTRING, this owns | 
|  | it.  */ | 
|  | gdb::unique_xmalloc_ptr<char> stabstring_storage; | 
|  | int len = strlen (stabstring); | 
|  |  | 
|  | while (stabstring[len - 1] == '\\') | 
|  | { | 
|  | SYMR sh2; | 
|  | char *stabstring1 = stabstring; | 
|  | char *stabstring2; | 
|  | int len2; | 
|  |  | 
|  | /* Ignore continuation char from 1st string.  */ | 
|  | len--; | 
|  |  | 
|  | /* Read next stabstring.  */ | 
|  | cur_sdx++; | 
|  | (*swap_sym_in) (cur_bfd, | 
|  | (((char *) debug_info->external_sym) | 
|  | + (fh->isymBase + cur_sdx) | 
|  | * external_sym_size), | 
|  | &sh2); | 
|  | stabstring2 = debug_info->ss + fh->issBase + sh2.iss; | 
|  | len2 = strlen (stabstring2); | 
|  |  | 
|  | /* Concatenate stabstring2 with stabstring1.  */ | 
|  | if (stabstring_storage != nullptr) | 
|  | { | 
|  | stabstring_storage.reset | 
|  | ((char *) xrealloc (stabstring_storage.release (), | 
|  | len + len2 + 1)); | 
|  | stabstring = stabstring_storage.get (); | 
|  | } | 
|  | else | 
|  | { | 
|  | stabstring_storage.reset | 
|  | ((char *) xmalloc (len + len2 + 1)); | 
|  | stabstring = stabstring_storage.get (); | 
|  | strcpy (stabstring, stabstring1); | 
|  | } | 
|  | strcpy (stabstring + len, stabstring2); | 
|  | len += len2; | 
|  | } | 
|  |  | 
|  | switch (type_code) | 
|  | { | 
|  | const char *p; | 
|  |  | 
|  | /* Standard, external, non-debugger, symbols.  */ | 
|  |  | 
|  | case N_TEXT | N_EXT: | 
|  | case N_NBTEXT | N_EXT: | 
|  | goto record_it; | 
|  |  | 
|  | case N_DATA | N_EXT: | 
|  | case N_NBDATA | N_EXT: | 
|  | goto record_it; | 
|  |  | 
|  | case N_BSS: | 
|  | case N_BSS | N_EXT: | 
|  | case N_NBBSS | N_EXT: | 
|  | case N_SETV | N_EXT:		/* FIXME, is this in BSS?  */ | 
|  | goto record_it; | 
|  |  | 
|  | case N_ABS | N_EXT: | 
|  | record_it: | 
|  | continue; | 
|  |  | 
|  | /* Standard, local, non-debugger, symbols.  */ | 
|  |  | 
|  | case N_NBTEXT: | 
|  |  | 
|  | /* We need to be able to deal with both N_FN or | 
|  | N_TEXT, because we have no way of knowing | 
|  | whether the sys-supplied ld or GNU ld was used | 
|  | to make the executable.  Sequents throw in | 
|  | another wrinkle -- they renumbered N_FN.  */ | 
|  |  | 
|  | case N_FN: | 
|  | case N_FN_SEQ: | 
|  | case N_TEXT: | 
|  | continue; | 
|  |  | 
|  | case N_DATA: | 
|  | goto record_it; | 
|  |  | 
|  | case N_UNDF | N_EXT: | 
|  | continue;		/* Just undefined, not COMMON.  */ | 
|  |  | 
|  | case N_UNDF: | 
|  | continue; | 
|  |  | 
|  | /* Lots of symbol types we can just ignore.  */ | 
|  |  | 
|  | case N_ABS: | 
|  | case N_NBDATA: | 
|  | case N_NBBSS: | 
|  | continue; | 
|  |  | 
|  | /* Keep going . . .  */ | 
|  |  | 
|  | /* | 
|  | * Special symbol types for GNU | 
|  | */ | 
|  | case N_INDR: | 
|  | case N_INDR | N_EXT: | 
|  | case N_SETA: | 
|  | case N_SETA | N_EXT: | 
|  | case N_SETT: | 
|  | case N_SETT | N_EXT: | 
|  | case N_SETD: | 
|  | case N_SETD | N_EXT: | 
|  | case N_SETB: | 
|  | case N_SETB | N_EXT: | 
|  | case N_SETV: | 
|  | continue; | 
|  |  | 
|  | /* | 
|  | * Debugger symbols | 
|  | */ | 
|  |  | 
|  | case N_SO: | 
|  | { | 
|  | static int prev_so_symnum = -10; | 
|  | const char *basename; | 
|  |  | 
|  | /* A zero value is probably an indication for the | 
|  | SunPRO 3.0 compiler.  dbx_end_psymtab explicitly tests | 
|  | for zero, so don't relocate it.  */ | 
|  |  | 
|  | if (sh.value == 0 | 
|  | && gdbarch_sofun_address_maybe_missing (gdbarch)) | 
|  | textlow_not_set = 1; | 
|  | else | 
|  | textlow_not_set = 0; | 
|  |  | 
|  | if (prev_so_symnum != symnum - 1) | 
|  | {		/* Here if prev stab wasn't N_SO.  */ | 
|  | if (pst) | 
|  | { | 
|  | pst = (legacy_psymtab *) 0; | 
|  | includes_used = 0; | 
|  | dependencies_used = 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | prev_so_symnum = symnum; | 
|  |  | 
|  | /* End the current partial symtab and start a | 
|  | new one.  */ | 
|  |  | 
|  | /* SET_NAMESTRING ();*/ | 
|  | namestring = stabstring; | 
|  |  | 
|  | /* Null name means end of .o file.  Don't start a new | 
|  | one.  */ | 
|  | if (*namestring == '\000') | 
|  | continue; | 
|  |  | 
|  | /* Some compilers (including gcc) emit a pair of | 
|  | initial N_SOs.  The first one is a directory name; | 
|  | the second the file name.  If pst exists, is | 
|  | empty, and has a filename ending in '/', we assume | 
|  | the previous N_SO was a directory name.  */ | 
|  | basename = lbasename (namestring); | 
|  | if (basename != namestring && *basename == '\000') | 
|  | continue;		/* Simply ignore directory | 
|  | name SOs.  */ | 
|  |  | 
|  | /* Some other compilers (C++ ones in particular) emit | 
|  | useless SOs for non-existant .c files.  We ignore | 
|  | all subsequent SOs that immediately follow the | 
|  | first.  */ | 
|  |  | 
|  | if (!pst) | 
|  | pst = save_pst; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | case N_BINCL: | 
|  | continue; | 
|  |  | 
|  | case N_SOL: | 
|  | { | 
|  | enum language tmp_language; | 
|  |  | 
|  | /* Mark down an include file in the current psymtab.  */ | 
|  |  | 
|  | /* SET_NAMESTRING (); */ | 
|  | namestring = stabstring; | 
|  |  | 
|  | tmp_language | 
|  | = deduce_language_from_filename (namestring); | 
|  |  | 
|  | /* Only change the psymtab's language if we've | 
|  | learned something useful (eg. tmp_language is not | 
|  | language_unknown).  In addition, to match what | 
|  | start_subfile does, never change from C++ to | 
|  | C.  */ | 
|  | if (tmp_language != language_unknown | 
|  | && (tmp_language != language_c | 
|  | || psymtab_language != language_cplus)) | 
|  | psymtab_language = tmp_language; | 
|  |  | 
|  | /* In C++, one may expect the same filename to come | 
|  | round many times, when code is coming alternately | 
|  | from the main file and from inline functions in | 
|  | other files.  So I check to see if this is a file | 
|  | we've seen before -- either the main source file, | 
|  | or a previously included file. | 
|  |  | 
|  | This seems to be a lot of time to be spending on | 
|  | N_SOL, but things like "break c-exp.y:435" need to | 
|  | work (I suppose the psymtab_include_list could be | 
|  | hashed or put in a binary tree, if profiling shows | 
|  | this is a major hog).  */ | 
|  | if (pst && filename_cmp (namestring, pst->filename) == 0) | 
|  | continue; | 
|  |  | 
|  | { | 
|  | int i; | 
|  |  | 
|  | for (i = 0; i < includes_used; i++) | 
|  | if (filename_cmp (namestring, | 
|  | psymtab_include_list[i]) == 0) | 
|  | { | 
|  | i = -1; | 
|  | break; | 
|  | } | 
|  | if (i == -1) | 
|  | continue; | 
|  | } | 
|  |  | 
|  | psymtab_include_list[includes_used++] = namestring; | 
|  | if (includes_used >= includes_allocated) | 
|  | { | 
|  | const char **orig = psymtab_include_list; | 
|  |  | 
|  | psymtab_include_list = (const char **) | 
|  | alloca ((includes_allocated *= 2) * | 
|  | sizeof (const char *)); | 
|  | memcpy (psymtab_include_list, orig, | 
|  | includes_used * sizeof (const char *)); | 
|  | } | 
|  | continue; | 
|  | } | 
|  | case N_LSYM:	    /* Typedef or automatic variable.  */ | 
|  | case N_STSYM:	    /* Data seg var -- static  */ | 
|  | case N_LCSYM:	    /* BSS      "  */ | 
|  | case N_ROSYM:	    /* Read-only data seg var -- static.  */ | 
|  | case N_NBSTS:	    /* Gould nobase.  */ | 
|  | case N_NBLCS:	    /* symbols.  */ | 
|  | case N_FUN: | 
|  | case N_GSYM:	    /* Global (extern) variable; can be | 
|  | data or bss (sigh FIXME).  */ | 
|  |  | 
|  | /* Following may probably be ignored; I'll leave them here | 
|  | for now (until I do Pascal and Modula 2 extensions).  */ | 
|  |  | 
|  | case N_PC:	    /* I may or may not need this; I | 
|  | suspect not.  */ | 
|  | case N_M2C:	    /* I suspect that I can ignore this | 
|  | here.  */ | 
|  | case N_SCOPE:	    /* Same.  */ | 
|  |  | 
|  | /*    SET_NAMESTRING (); */ | 
|  | namestring = stabstring; | 
|  | p = (char *) strchr (namestring, ':'); | 
|  | if (!p) | 
|  | continue;	    /* Not a debugging symbol.  */ | 
|  |  | 
|  |  | 
|  |  | 
|  | /* Main processing section for debugging symbols which | 
|  | the initial read through the symbol tables needs to | 
|  | worry about.  If we reach this point, the symbol | 
|  | which we are considering is definitely one we are | 
|  | interested in.  p must also contain the (valid) | 
|  | index into the namestring which indicates the | 
|  | debugging type symbol.  */ | 
|  |  | 
|  | switch (p[1]) | 
|  | { | 
|  | case 'S': | 
|  | pst->add_psymbol (gdb::string_view (namestring, | 
|  | p - namestring), | 
|  | true, VAR_DOMAIN, LOC_STATIC, | 
|  | SECT_OFF_DATA (objfile), | 
|  | psymbol_placement::STATIC, | 
|  | sh.value, | 
|  | psymtab_language, | 
|  | partial_symtabs, objfile); | 
|  | continue; | 
|  | case 'G': | 
|  | /* The addresses in these entries are reported | 
|  | to be wrong.  See the code that reads 'G's | 
|  | for symtabs.  */ | 
|  | pst->add_psymbol (gdb::string_view (namestring, | 
|  | p - namestring), | 
|  | true, VAR_DOMAIN, LOC_STATIC, | 
|  | SECT_OFF_DATA (objfile), | 
|  | psymbol_placement::GLOBAL, | 
|  | sh.value, | 
|  | psymtab_language, | 
|  | partial_symtabs, objfile); | 
|  | continue; | 
|  |  | 
|  | case 'T': | 
|  | /* When a 'T' entry is defining an anonymous enum, it | 
|  | may have a name which is the empty string, or a | 
|  | single space.  Since they're not really defining a | 
|  | symbol, those shouldn't go in the partial symbol | 
|  | table.  We do pick up the elements of such enums at | 
|  | 'check_enum:', below.  */ | 
|  | if (p >= namestring + 2 | 
|  | || (p == namestring + 1 | 
|  | && namestring[0] != ' ')) | 
|  | { | 
|  | pst->add_psymbol | 
|  | (gdb::string_view (namestring, p - namestring), | 
|  | true, STRUCT_DOMAIN, LOC_TYPEDEF, -1, | 
|  | psymbol_placement::STATIC, 0, psymtab_language, | 
|  | partial_symtabs, objfile); | 
|  | if (p[2] == 't') | 
|  | { | 
|  | /* Also a typedef with the same name.  */ | 
|  | pst->add_psymbol | 
|  | (gdb::string_view (namestring, | 
|  | p - namestring), | 
|  | true, VAR_DOMAIN, LOC_TYPEDEF, -1, | 
|  | psymbol_placement::STATIC, 0, | 
|  | psymtab_language, | 
|  | partial_symtabs, objfile); | 
|  | p += 1; | 
|  | } | 
|  | } | 
|  | goto check_enum; | 
|  | case 't': | 
|  | if (p != namestring)	/* a name is there, not | 
|  | just :T...  */ | 
|  | { | 
|  | pst->add_psymbol | 
|  | (gdb::string_view (namestring, | 
|  | p - namestring), | 
|  | true, VAR_DOMAIN, LOC_TYPEDEF, -1, | 
|  | psymbol_placement::STATIC, 0, psymtab_language, | 
|  | partial_symtabs, objfile); | 
|  | } | 
|  | check_enum: | 
|  | /* If this is an enumerated type, we need to add | 
|  | all the enum constants to the partial symbol | 
|  | table.  This does not cover enums without names, | 
|  | e.g. "enum {a, b} c;" in C, but fortunately | 
|  | those are rare.  There is no way for GDB to find | 
|  | those from the enum type without spending too | 
|  | much time on it.  Thus to solve this problem, | 
|  | the compiler needs to put out the enum in a | 
|  | nameless type.  GCC2 does this.  */ | 
|  |  | 
|  | /* We are looking for something of the form | 
|  | <name> ":" ("t" | "T") [<number> "="] "e" | 
|  | {<constant> ":" <value> ","} ";".  */ | 
|  |  | 
|  | /* Skip over the colon and the 't' or 'T'.  */ | 
|  | p += 2; | 
|  | /* This type may be given a number.  Also, numbers | 
|  | can come in pairs like (0,26).  Skip over it.  */ | 
|  | while ((*p >= '0' && *p <= '9') | 
|  | || *p == '(' || *p == ',' || *p == ')' | 
|  | || *p == '=') | 
|  | p++; | 
|  |  | 
|  | if (*p++ == 'e') | 
|  | { | 
|  | /* The aix4 compiler emits extra crud before | 
|  | the members.  */ | 
|  | if (*p == '-') | 
|  | { | 
|  | /* Skip over the type (?).  */ | 
|  | while (*p != ':') | 
|  | p++; | 
|  |  | 
|  | /* Skip over the colon.  */ | 
|  | p++; | 
|  | } | 
|  |  | 
|  | /* We have found an enumerated type.  */ | 
|  | /* According to comments in read_enum_type | 
|  | a comma could end it instead of a semicolon. | 
|  | I don't know where that happens. | 
|  | Accept either.  */ | 
|  | while (*p && *p != ';' && *p != ',') | 
|  | { | 
|  | const char *q; | 
|  |  | 
|  | /* Check for and handle cretinous dbx | 
|  | symbol name continuation!  */ | 
|  | if (*p == '\\' || (*p == '?' && p[1] == '\0')) | 
|  | p = next_symbol_text (objfile); | 
|  |  | 
|  | /* Point to the character after the name | 
|  | of the enum constant.  */ | 
|  | for (q = p; *q && *q != ':'; q++) | 
|  | ; | 
|  | /* Note that the value doesn't matter for | 
|  | enum constants in psymtabs, just in | 
|  | symtabs.  */ | 
|  | pst->add_psymbol (gdb::string_view (p, | 
|  | q - p), | 
|  | true, VAR_DOMAIN, | 
|  | LOC_CONST, -1, | 
|  | psymbol_placement::STATIC, | 
|  | 0, psymtab_language, | 
|  | partial_symtabs, objfile); | 
|  | /* Point past the name.  */ | 
|  | p = q; | 
|  | /* Skip over the value.  */ | 
|  | while (*p && *p != ',') | 
|  | p++; | 
|  | /* Advance past the comma.  */ | 
|  | if (*p) | 
|  | p++; | 
|  | } | 
|  | } | 
|  | continue; | 
|  | case 'c': | 
|  | /* Constant, e.g. from "const" in Pascal.  */ | 
|  | pst->add_psymbol (gdb::string_view (namestring, | 
|  | p - namestring), | 
|  | true, VAR_DOMAIN, LOC_CONST, -1, | 
|  | psymbol_placement::STATIC, | 
|  | 0, psymtab_language, | 
|  | partial_symtabs, objfile); | 
|  | continue; | 
|  |  | 
|  | case 'f': | 
|  | if (! pst) | 
|  | { | 
|  | std::string copy (namestring, p); | 
|  | function_outside_compilation_unit_complaint | 
|  | (copy.c_str ()); | 
|  | } | 
|  | pst->add_psymbol (gdb::string_view (namestring, | 
|  | p - namestring), | 
|  | true, VAR_DOMAIN, LOC_BLOCK, | 
|  | SECT_OFF_TEXT (objfile), | 
|  | psymbol_placement::STATIC, | 
|  | sh.value, | 
|  | psymtab_language, | 
|  | partial_symtabs, objfile); | 
|  | continue; | 
|  |  | 
|  | /* Global functions were ignored here, but now they | 
|  | are put into the global psymtab like one would | 
|  | expect.  They're also in the minimal symbol | 
|  | table.  */ | 
|  | case 'F': | 
|  | if (! pst) | 
|  | { | 
|  | std::string copy (namestring, p); | 
|  | function_outside_compilation_unit_complaint | 
|  | (copy.c_str ()); | 
|  | } | 
|  | pst->add_psymbol (gdb::string_view (namestring, | 
|  | p - namestring), | 
|  | true, VAR_DOMAIN, LOC_BLOCK, | 
|  | SECT_OFF_TEXT (objfile), | 
|  | psymbol_placement::GLOBAL, | 
|  | sh.value, | 
|  | psymtab_language, | 
|  | partial_symtabs, objfile); | 
|  | continue; | 
|  |  | 
|  | /* Two things show up here (hopefully); static | 
|  | symbols of local scope (static used inside | 
|  | braces) or extensions of structure symbols.  We | 
|  | can ignore both.  */ | 
|  | case 'V': | 
|  | case '(': | 
|  | case '0': | 
|  | case '1': | 
|  | case '2': | 
|  | case '3': | 
|  | case '4': | 
|  | case '5': | 
|  | case '6': | 
|  | case '7': | 
|  | case '8': | 
|  | case '9': | 
|  | case '-': | 
|  | case '#':		/* For symbol identification (used | 
|  | in live ranges).  */ | 
|  | continue; | 
|  |  | 
|  | case ':': | 
|  | /* It is a C++ nested symbol.  We don't need to | 
|  | record it (I don't think); if we try to look up | 
|  | foo::bar::baz, then symbols for the symtab | 
|  | containing foo should get read in, I think.  */ | 
|  | /* Someone says sun cc puts out symbols like | 
|  | /foo/baz/maclib::/usr/local/bin/maclib, | 
|  | which would get here with a symbol type of ':'.  */ | 
|  | continue; | 
|  |  | 
|  | default: | 
|  | /* Unexpected symbol descriptor.  The second and | 
|  | subsequent stabs of a continued stab can show up | 
|  | here.  The question is whether they ever can | 
|  | mimic a normal stab--it would be nice if not, | 
|  | since we certainly don't want to spend the time | 
|  | searching to the end of every string looking for | 
|  | a backslash.  */ | 
|  |  | 
|  | complaint (_("unknown symbol descriptor `%c'"), p[1]); | 
|  |  | 
|  | /* Ignore it; perhaps it is an extension that we don't | 
|  | know about.  */ | 
|  | continue; | 
|  | } | 
|  |  | 
|  | case N_EXCL: | 
|  | continue; | 
|  |  | 
|  | case N_ENDM: | 
|  | /* Solaris 2 end of module, finish current partial | 
|  | symbol table.  dbx_end_psymtab will set the | 
|  | high text address of PST to the proper value, | 
|  | which is necessary if a module compiled without | 
|  | debugging info follows this module.  */ | 
|  | if (pst | 
|  | && gdbarch_sofun_address_maybe_missing (gdbarch)) | 
|  | { | 
|  | pst = (legacy_psymtab *) 0; | 
|  | includes_used = 0; | 
|  | dependencies_used = 0; | 
|  | } | 
|  | continue; | 
|  |  | 
|  | case N_RBRAC: | 
|  | if (sh.value > save_pst->raw_text_high ()) | 
|  | save_pst->set_text_high (sh.value); | 
|  | continue; | 
|  | case N_EINCL: | 
|  | case N_DSLINE: | 
|  | case N_BSLINE: | 
|  | case N_SSYM:		/* Claim: Structure or union | 
|  | element.  Hopefully, I can | 
|  | ignore this.  */ | 
|  | case N_ENTRY:		/* Alternate entry point; can | 
|  | ignore.  */ | 
|  | case N_MAIN:		/* Can definitely ignore this.   */ | 
|  | case N_CATCH:		/* These are GNU C++ extensions.  */ | 
|  | case N_EHDECL:	/* that can safely be ignored here.  */ | 
|  | case N_LENG: | 
|  | case N_BCOMM: | 
|  | case N_ECOMM: | 
|  | case N_ECOML: | 
|  | case N_FNAME: | 
|  | case N_SLINE: | 
|  | case N_RSYM: | 
|  | case N_PSYM: | 
|  | case N_LBRAC: | 
|  | case N_NSYMS:		/* Ultrix 4.0: symbol count */ | 
|  | case N_DEFD:			/* GNU Modula-2 */ | 
|  | case N_ALIAS:		/* SunPro F77: alias name, ignore | 
|  | for now.  */ | 
|  |  | 
|  | case N_OBJ:		/* Useless types from Solaris.  */ | 
|  | case N_OPT: | 
|  | /* These symbols aren't interesting; don't worry about | 
|  | them.  */ | 
|  |  | 
|  | continue; | 
|  |  | 
|  | default: | 
|  | /* If we haven't found it yet, ignore it.  It's | 
|  | probably some new type we don't know about yet.  */ | 
|  | complaint (_("unknown symbol type %s"), | 
|  | hex_string (type_code)); /* CUR_SYMBOL_TYPE */ | 
|  | continue; | 
|  | } | 
|  | } | 
|  | /* end - Handle continuation */ | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | for (cur_sdx = 0; cur_sdx < fh->csym;) | 
|  | { | 
|  | char *sym_name; | 
|  | enum address_class theclass; | 
|  | CORE_ADDR minsym_value; | 
|  | short section = -1; | 
|  |  | 
|  | (*swap_sym_in) (cur_bfd, | 
|  | ((char *) debug_info->external_sym | 
|  | + ((fh->isymBase + cur_sdx) | 
|  | * external_sym_size)), | 
|  | &sh); | 
|  |  | 
|  | if (ECOFF_IS_STAB (&sh)) | 
|  | { | 
|  | cur_sdx++; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | /* Non absolute static symbols go into the minimal table.  */ | 
|  | if (SC_IS_UNDEF (sh.sc) || sh.sc == scNil | 
|  | || (sh.index == indexNil | 
|  | && (sh.st != stStatic || sh.sc == scAbs))) | 
|  | { | 
|  | /* FIXME, premature?  */ | 
|  | cur_sdx++; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | sym_name = debug_info->ss + fh->issBase + sh.iss; | 
|  |  | 
|  | minsym_value = sh.value; | 
|  |  | 
|  | switch (sh.sc) | 
|  | { | 
|  | case scText: | 
|  | case scRConst: | 
|  | /* The value of a stEnd symbol is the displacement from the | 
|  | corresponding start symbol value, do not relocate it.  */ | 
|  | if (sh.st != stEnd) | 
|  | section = SECT_OFF_TEXT (objfile); | 
|  | break; | 
|  | case scData: | 
|  | case scSData: | 
|  | case scRData: | 
|  | case scPData: | 
|  | case scXData: | 
|  | section = SECT_OFF_DATA (objfile); | 
|  | break; | 
|  | case scBss: | 
|  | case scSBss: | 
|  | section = SECT_OFF_BSS (objfile); | 
|  | break; | 
|  | } | 
|  |  | 
|  | switch (sh.st) | 
|  | { | 
|  | CORE_ADDR high; | 
|  | CORE_ADDR procaddr; | 
|  | int new_sdx; | 
|  |  | 
|  | case stStaticProc: | 
|  | reader.record_with_info (sym_name, minsym_value, | 
|  | mst_file_text, | 
|  | SECT_OFF_TEXT (objfile)); | 
|  |  | 
|  | /* FALLTHROUGH */ | 
|  |  | 
|  | case stProc: | 
|  | /* Ignore all parameter symbol records.  */ | 
|  | if (sh.index >= hdr->iauxMax) | 
|  | { | 
|  | /* Should not happen, but does when cross-compiling | 
|  | with the MIPS compiler.  FIXME -- pull later.  */ | 
|  | index_complaint (sym_name); | 
|  | new_sdx = cur_sdx + 1;	/* Don't skip at all.  */ | 
|  | } | 
|  | else | 
|  | new_sdx = AUX_GET_ISYM (fh->fBigendian, | 
|  | (debug_info->external_aux | 
|  | + fh->iauxBase | 
|  | + sh.index)); | 
|  |  | 
|  | if (new_sdx <= cur_sdx) | 
|  | { | 
|  | /* This should not happen either... FIXME.  */ | 
|  | complaint (_("bad proc end in aux found from symbol %s"), | 
|  | sym_name); | 
|  | new_sdx = cur_sdx + 1;	/* Don't skip backward.  */ | 
|  | } | 
|  |  | 
|  | /* For stProc symbol records, we need to check the | 
|  | storage class as well, as only (stProc, scText) | 
|  | entries represent "real" procedures - See the | 
|  | Compaq document titled "Object File / Symbol Table | 
|  | Format Specification" for more information.  If the | 
|  | storage class is not scText, we discard the whole | 
|  | block of symbol records for this stProc.  */ | 
|  | if (sh.st == stProc && sh.sc != scText) | 
|  | goto skip; | 
|  |  | 
|  | /* Usually there is a local and a global stProc symbol | 
|  | for a function.  This means that the function name | 
|  | has already been entered into the minimal symbol table | 
|  | while processing the global symbols in pass 2 above. | 
|  | One notable exception is the PROGRAM name from | 
|  | f77 compiled executables, it is only put out as | 
|  | local stProc symbol, and a global MAIN__ stProc symbol | 
|  | points to it.  It doesn't matter though, as gdb is | 
|  | still able to find the PROGRAM name via the partial | 
|  | symbol table, and the MAIN__ symbol via the minimal | 
|  | symbol table.  */ | 
|  | if (sh.st == stProc) | 
|  | pst->add_psymbol (sym_name, true, | 
|  | VAR_DOMAIN, LOC_BLOCK, | 
|  | section, | 
|  | psymbol_placement::GLOBAL, | 
|  | sh.value, psymtab_language, | 
|  | partial_symtabs, objfile); | 
|  | else | 
|  | pst->add_psymbol (sym_name, true, | 
|  | VAR_DOMAIN, LOC_BLOCK, | 
|  | section, | 
|  | psymbol_placement::STATIC, | 
|  | sh.value, psymtab_language, | 
|  | partial_symtabs, objfile); | 
|  |  | 
|  | procaddr = sh.value; | 
|  |  | 
|  | cur_sdx = new_sdx; | 
|  | (*swap_sym_in) (cur_bfd, | 
|  | ((char *) debug_info->external_sym | 
|  | + ((fh->isymBase + cur_sdx - 1) | 
|  | * external_sym_size)), | 
|  | &sh); | 
|  | if (sh.st != stEnd) | 
|  | continue; | 
|  |  | 
|  | /* Kludge for Irix 5.2 zero fh->adr.  */ | 
|  | if (!relocatable | 
|  | && (!pst->text_low_valid | 
|  | || procaddr < pst->raw_text_low ())) | 
|  | pst->set_text_low (procaddr); | 
|  |  | 
|  | high = procaddr + sh.value; | 
|  | if (high > pst->raw_text_high ()) | 
|  | pst->set_text_high (high); | 
|  | continue; | 
|  |  | 
|  | case stStatic:	/* Variable */ | 
|  | if (SC_IS_DATA (sh.sc)) | 
|  | reader.record_with_info (sym_name, minsym_value, | 
|  | mst_file_data, | 
|  | SECT_OFF_DATA (objfile)); | 
|  | else | 
|  | reader.record_with_info (sym_name, minsym_value, | 
|  | mst_file_bss, | 
|  | SECT_OFF_BSS (objfile)); | 
|  | theclass = LOC_STATIC; | 
|  | break; | 
|  |  | 
|  | case stIndirect:	/* Irix5 forward declaration */ | 
|  | /* Skip forward declarations from Irix5 cc.  */ | 
|  | goto skip; | 
|  |  | 
|  | case stTypedef:	/* Typedef */ | 
|  | /* Skip typedefs for forward declarations and opaque | 
|  | structs from alpha and mips cc.  */ | 
|  | if (sh.iss == 0 || has_opaque_xref (fh, &sh)) | 
|  | goto skip; | 
|  | theclass = LOC_TYPEDEF; | 
|  | break; | 
|  |  | 
|  | case stConstant:	/* Constant decl */ | 
|  | theclass = LOC_CONST; | 
|  | break; | 
|  |  | 
|  | case stUnion: | 
|  | case stStruct: | 
|  | case stEnum: | 
|  | case stBlock:	/* { }, str, un, enum */ | 
|  | /* Do not create a partial symbol for cc unnamed aggregates | 
|  | and gcc empty aggregates.  */ | 
|  | if ((sh.sc == scInfo | 
|  | || SC_IS_COMMON (sh.sc)) | 
|  | && sh.iss != 0 | 
|  | && sh.index != cur_sdx + 2) | 
|  | { | 
|  | pst->add_psymbol (sym_name, true, | 
|  | STRUCT_DOMAIN, LOC_TYPEDEF, -1, | 
|  | psymbol_placement::STATIC, | 
|  | 0, psymtab_language, | 
|  | partial_symtabs, objfile); | 
|  | } | 
|  | handle_psymbol_enumerators (objfile, partial_symtabs, | 
|  | pst, fh, sh.st, sh.value); | 
|  |  | 
|  | /* Skip over the block.  */ | 
|  | new_sdx = sh.index; | 
|  | if (new_sdx <= cur_sdx) | 
|  | { | 
|  | /* This happens with the Ultrix kernel.  */ | 
|  | complaint (_("bad aux index at block symbol %s"), | 
|  | sym_name); | 
|  | new_sdx = cur_sdx + 1;	/* Don't skip backward.  */ | 
|  | } | 
|  | cur_sdx = new_sdx; | 
|  | continue; | 
|  |  | 
|  | case stFile:	/* File headers */ | 
|  | case stLabel:	/* Labels */ | 
|  | case stEnd:	/* Ends of files */ | 
|  | goto skip; | 
|  |  | 
|  | case stLocal:	/* Local variables */ | 
|  | /* Normally these are skipped because we skip over | 
|  | all blocks we see.  However, these can occur | 
|  | as visible symbols in a .h file that contains code.  */ | 
|  | goto skip; | 
|  |  | 
|  | default: | 
|  | /* Both complaints are valid:  one gives symbol sym_name, | 
|  | the other the offending symbol type.  */ | 
|  | complaint (_("unknown local symbol %s"), | 
|  | sym_name); | 
|  | complaint (_("with type %d"), sh.st); | 
|  | cur_sdx++; | 
|  | continue; | 
|  | } | 
|  | /* Use this gdb symbol.  */ | 
|  | pst->add_psymbol (sym_name, true, | 
|  | VAR_DOMAIN, theclass, section, | 
|  | psymbol_placement::STATIC, | 
|  | sh.value, psymtab_language, | 
|  | partial_symtabs, objfile); | 
|  | skip: | 
|  | cur_sdx++;	/* Go to next file symbol.  */ | 
|  | } | 
|  |  | 
|  | /* Now do enter the external symbols.  */ | 
|  | ext_ptr = &extern_tab[fdr_to_pst[f_idx].globals_offset]; | 
|  | cur_sdx = fdr_to_pst[f_idx].n_globals; | 
|  | PST_PRIVATE (save_pst)->extern_count = cur_sdx; | 
|  | PST_PRIVATE (save_pst)->extern_tab = ext_ptr; | 
|  | for (; --cur_sdx >= 0; ext_ptr++) | 
|  | { | 
|  | enum address_class theclass; | 
|  | SYMR *psh; | 
|  | CORE_ADDR svalue; | 
|  | short section; | 
|  |  | 
|  | gdb_assert (ext_ptr->ifd == f_idx); | 
|  |  | 
|  | psh = &ext_ptr->asym; | 
|  |  | 
|  | /* Do not add undefined symbols to the partial symbol table.  */ | 
|  | if (SC_IS_UNDEF (psh->sc) || psh->sc == scNil) | 
|  | continue; | 
|  |  | 
|  | svalue = psh->value; | 
|  | switch (psh->sc) | 
|  | { | 
|  | default: | 
|  | case scText: | 
|  | case scRConst: | 
|  | section = SECT_OFF_TEXT (objfile); | 
|  | break; | 
|  | case scData: | 
|  | case scSData: | 
|  | case scRData: | 
|  | case scPData: | 
|  | case scXData: | 
|  | section = SECT_OFF_DATA (objfile); | 
|  | break; | 
|  | case scBss: | 
|  | case scSBss: | 
|  | section = SECT_OFF_BSS (objfile); | 
|  | break; | 
|  | } | 
|  |  | 
|  | switch (psh->st) | 
|  | { | 
|  | case stNil: | 
|  | /* These are generated for static symbols in .o files, | 
|  | ignore them.  */ | 
|  | continue; | 
|  | case stProc: | 
|  | case stStaticProc: | 
|  | /* External procedure symbols have been entered | 
|  | into the minimal symbol table in pass 2 above. | 
|  | Ignore them, as parse_external will ignore them too.  */ | 
|  | continue; | 
|  | case stLabel: | 
|  | theclass = LOC_LABEL; | 
|  | break; | 
|  | default: | 
|  | unknown_ext_complaint (debug_info->ssext + psh->iss); | 
|  | /* Pretend it's global.  */ | 
|  | /* Fall through.  */ | 
|  | case stGlobal: | 
|  | /* Global common symbols are resolved by the runtime loader, | 
|  | ignore them.  */ | 
|  | if (SC_IS_COMMON (psh->sc)) | 
|  | continue; | 
|  |  | 
|  | theclass = LOC_STATIC; | 
|  | break; | 
|  | } | 
|  | char *sym_name = debug_info->ssext + psh->iss; | 
|  | pst->add_psymbol (sym_name, true, | 
|  | VAR_DOMAIN, theclass, | 
|  | section, | 
|  | psymbol_placement::GLOBAL, | 
|  | svalue, psymtab_language, | 
|  | partial_symtabs, objfile); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Link pst to FDR.  dbx_end_psymtab returns NULL if the psymtab was | 
|  | empty and put on the free list.  */ | 
|  | fdr_to_pst[f_idx].pst | 
|  | = dbx_end_psymtab (objfile, partial_symtabs, save_pst, | 
|  | psymtab_include_list, includes_used, | 
|  | -1, save_pst->raw_text_high (), | 
|  | dependency_list, dependencies_used, | 
|  | textlow_not_set); | 
|  | includes_used = 0; | 
|  | dependencies_used = 0; | 
|  |  | 
|  | /* The objfile has its functions reordered if this partial symbol | 
|  | table overlaps any other partial symbol table. | 
|  | We cannot assume a reordered objfile if a partial symbol table | 
|  | is contained within another partial symbol table, as partial symbol | 
|  | tables for include files with executable code are contained | 
|  | within the partial symbol table for the including source file, | 
|  | and we do not want to flag the objfile reordered for these cases. | 
|  |  | 
|  | This strategy works well for Irix-5.2 shared libraries, but we | 
|  | might have to use a more elaborate (and slower) algorithm for | 
|  | other cases.  */ | 
|  | save_pst = fdr_to_pst[f_idx].pst; | 
|  | if (save_pst != NULL | 
|  | && save_pst->text_low_valid | 
|  | && !(objfile->flags & OBJF_REORDERED)) | 
|  | { | 
|  | for (partial_symtab *iter : partial_symtabs->range ()) | 
|  | { | 
|  | if (save_pst != iter | 
|  | && save_pst->raw_text_low () >= iter->raw_text_low () | 
|  | && save_pst->raw_text_low () < iter->raw_text_high () | 
|  | && save_pst->raw_text_high () > iter->raw_text_high ()) | 
|  | { | 
|  | objfile->flags |= OBJF_REORDERED; | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Now scan the FDRs for dependencies.  */ | 
|  | for (f_idx = 0; f_idx < hdr->ifdMax; f_idx++) | 
|  | { | 
|  | fh = f_idx + debug_info->fdr; | 
|  | pst = fdr_to_pst[f_idx].pst; | 
|  |  | 
|  | if (pst == NULL) | 
|  | continue; | 
|  |  | 
|  | /* This should catch stabs-in-ecoff.  */ | 
|  | if (fh->crfd <= 1) | 
|  | continue; | 
|  |  | 
|  | /* Skip the first file indirect entry as it is a self dependency for | 
|  | source files or a reverse .h -> .c dependency for header files.  */ | 
|  | pst->number_of_dependencies = 0; | 
|  | pst->dependencies | 
|  | = partial_symtabs->allocate_dependencies (fh->crfd - 1); | 
|  | for (s_idx = 1; s_idx < fh->crfd; s_idx++) | 
|  | { | 
|  | RFDT rh; | 
|  |  | 
|  | (*swap_rfd_in) (cur_bfd, | 
|  | ((char *) debug_info->external_rfd | 
|  | + (fh->rfdBase + s_idx) * external_rfd_size), | 
|  | &rh); | 
|  | if (rh < 0 || rh >= hdr->ifdMax) | 
|  | { | 
|  | complaint (_("bad file number %ld"), rh); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | /* Skip self dependencies of header files.  */ | 
|  | if (rh == f_idx) | 
|  | continue; | 
|  |  | 
|  | /* Do not add to dependency list if psymtab was empty.  */ | 
|  | if (fdr_to_pst[rh].pst == NULL) | 
|  | continue; | 
|  | pst->dependencies[pst->number_of_dependencies++] | 
|  | = fdr_to_pst[rh].pst; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Remove the dummy psymtab created for -O3 images above, if it is | 
|  | still empty, to enable the detection of stripped executables.  */ | 
|  | partial_symtab *pst_del = partial_symtabs->psymtabs; | 
|  | if (pst_del->next == NULL | 
|  | && pst_del->number_of_dependencies == 0 | 
|  | && pst_del->empty ()) | 
|  | partial_symtabs->discard_psymtab (pst_del); | 
|  | } | 
|  |  | 
|  | /* If the current psymbol has an enumerated type, we need to add | 
|  | all the enum constants to the partial symbol table.  */ | 
|  |  | 
|  | static void | 
|  | handle_psymbol_enumerators (struct objfile *objfile, | 
|  | psymtab_storage *partial_symtabs, | 
|  | partial_symtab *pst, | 
|  | FDR *fh, int stype, CORE_ADDR svalue) | 
|  | { | 
|  | const bfd_size_type external_sym_size = debug_swap->external_sym_size; | 
|  | void (*const swap_sym_in) (bfd *, void *, SYMR *) = debug_swap->swap_sym_in; | 
|  | char *ext_sym = ((char *) debug_info->external_sym | 
|  | + ((fh->isymBase + cur_sdx + 1) * external_sym_size)); | 
|  | SYMR sh; | 
|  | TIR tir; | 
|  |  | 
|  | switch (stype) | 
|  | { | 
|  | case stEnum: | 
|  | break; | 
|  |  | 
|  | case stBlock: | 
|  | /* It is an enumerated type if the next symbol entry is a stMember | 
|  | and its auxiliary index is indexNil or its auxiliary entry | 
|  | is a plain btNil or btVoid. | 
|  | Alpha cc -migrate enums are recognized by a zero index and | 
|  | a zero symbol value. | 
|  | DU 4.0 cc enums are recognized by a member type of btEnum without | 
|  | qualifiers and a zero symbol value.  */ | 
|  | (*swap_sym_in) (cur_bfd, ext_sym, &sh); | 
|  | if (sh.st != stMember) | 
|  | return; | 
|  |  | 
|  | if (sh.index == indexNil | 
|  | || (sh.index == 0 && svalue == 0)) | 
|  | break; | 
|  | (*debug_swap->swap_tir_in) (fh->fBigendian, | 
|  | &(debug_info->external_aux | 
|  | + fh->iauxBase + sh.index)->a_ti, | 
|  | &tir); | 
|  | if ((tir.bt != btNil | 
|  | && tir.bt != btVoid | 
|  | && (tir.bt != btEnum || svalue != 0)) | 
|  | || tir.tq0 != tqNil) | 
|  | return; | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return; | 
|  | } | 
|  |  | 
|  | for (;;) | 
|  | { | 
|  | char *name; | 
|  |  | 
|  | (*swap_sym_in) (cur_bfd, ext_sym, &sh); | 
|  | if (sh.st != stMember) | 
|  | break; | 
|  | name = debug_info->ss + cur_fdr->issBase + sh.iss; | 
|  |  | 
|  | /* Note that the value doesn't matter for enum constants | 
|  | in psymtabs, just in symtabs.  */ | 
|  | pst->add_psymbol (name, true, | 
|  | VAR_DOMAIN, LOC_CONST, -1, | 
|  | psymbol_placement::STATIC, 0, | 
|  | psymtab_language, partial_symtabs, objfile); | 
|  | ext_sym += external_sym_size; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Get the next symbol.  OBJFILE is unused.  */ | 
|  |  | 
|  | static const char * | 
|  | mdebug_next_symbol_text (struct objfile *objfile) | 
|  | { | 
|  | SYMR sh; | 
|  |  | 
|  | cur_sdx++; | 
|  | (*debug_swap->swap_sym_in) (cur_bfd, | 
|  | ((char *) debug_info->external_sym | 
|  | + ((cur_fdr->isymBase + cur_sdx) | 
|  | * debug_swap->external_sym_size)), | 
|  | &sh); | 
|  | return debug_info->ss + cur_fdr->issBase + sh.iss; | 
|  | } | 
|  |  | 
|  | /* Ancillary function to psymtab_to_symtab().  Does all the work | 
|  | for turning the partial symtab PST into a symtab, recurring | 
|  | first on all dependent psymtabs.  The argument FILENAME is | 
|  | only passed so we can see in debug stack traces what file | 
|  | is being read. | 
|  |  | 
|  | This function has a split personality, based on whether the | 
|  | symbol table contains ordinary ecoff symbols, or stabs-in-ecoff. | 
|  | The flow of control and even the memory allocation differs.  FIXME.  */ | 
|  |  | 
|  | static void | 
|  | mdebug_expand_psymtab (legacy_psymtab *pst, struct objfile *objfile) | 
|  | { | 
|  | bfd_size_type external_sym_size; | 
|  | bfd_size_type external_pdr_size; | 
|  | void (*swap_sym_in) (bfd *, void *, SYMR *); | 
|  | void (*swap_pdr_in) (bfd *, void *, PDR *); | 
|  | int i; | 
|  | struct compunit_symtab *cust = NULL; | 
|  | FDR *fh; | 
|  | struct linetable *lines; | 
|  | CORE_ADDR lowest_pdr_addr = 0; | 
|  | int last_symtab_ended = 0; | 
|  | const section_offsets §ion_offsets = objfile->section_offsets; | 
|  |  | 
|  | if (pst->readin) | 
|  | return; | 
|  | pst->readin = true; | 
|  |  | 
|  | /* Read in all partial symtabs on which this one is dependent. | 
|  | NOTE that we do have circular dependencies, sigh.  We solved | 
|  | that by setting pst->readin before this point.  */ | 
|  | pst->expand_dependencies (objfile); | 
|  |  | 
|  | /* Do nothing if this is a dummy psymtab.  */ | 
|  |  | 
|  | if (pst->empty () && !pst->text_low_valid && !pst->text_high_valid) | 
|  | return; | 
|  |  | 
|  | /* Now read the symbols for this symtab.  */ | 
|  |  | 
|  | cur_bfd = CUR_BFD (pst); | 
|  | debug_swap = DEBUG_SWAP (pst); | 
|  | debug_info = DEBUG_INFO (pst); | 
|  | pending_list = PENDING_LIST (pst); | 
|  | external_sym_size = debug_swap->external_sym_size; | 
|  | external_pdr_size = debug_swap->external_pdr_size; | 
|  | swap_sym_in = debug_swap->swap_sym_in; | 
|  | swap_pdr_in = debug_swap->swap_pdr_in; | 
|  | mdebugread_objfile = objfile; | 
|  | cur_fd = FDR_IDX (pst); | 
|  | fh = ((cur_fd == -1) | 
|  | ? NULL | 
|  | : debug_info->fdr + cur_fd); | 
|  | cur_fdr = fh; | 
|  |  | 
|  | /* See comment in parse_partial_symbols about the @stabs sentinel.  */ | 
|  | processing_gcc_compilation = 0; | 
|  | if (fh != NULL && fh->csym >= 2) | 
|  | { | 
|  | SYMR sh; | 
|  |  | 
|  | (*swap_sym_in) (cur_bfd, | 
|  | ((char *) debug_info->external_sym | 
|  | + (fh->isymBase + 1) * external_sym_size), | 
|  | &sh); | 
|  | if (strcmp (debug_info->ss + fh->issBase + sh.iss, | 
|  | stabs_symbol) == 0) | 
|  | { | 
|  | /* We indicate that this is a GCC compilation so that certain | 
|  | features will be enabled in stabsread/dbxread.  */ | 
|  | processing_gcc_compilation = 2; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (processing_gcc_compilation != 0) | 
|  | { | 
|  | struct gdbarch *gdbarch = objfile->arch (); | 
|  |  | 
|  | /* This symbol table contains stabs-in-ecoff entries.  */ | 
|  |  | 
|  | /* Parse local symbols first.  */ | 
|  |  | 
|  | if (fh->csym <= 2)	/* FIXME, this blows psymtab->symtab ptr.  */ | 
|  | { | 
|  | mdebugread_objfile = NULL; | 
|  | return; | 
|  | } | 
|  | for (cur_sdx = 2; cur_sdx < fh->csym; cur_sdx++) | 
|  | { | 
|  | SYMR sh; | 
|  | char *name; | 
|  | CORE_ADDR valu; | 
|  |  | 
|  | (*swap_sym_in) (cur_bfd, | 
|  | (((char *) debug_info->external_sym) | 
|  | + (fh->isymBase + cur_sdx) * external_sym_size), | 
|  | &sh); | 
|  | name = debug_info->ss + fh->issBase + sh.iss; | 
|  | valu = sh.value; | 
|  | /* XXX This is a hack.  It will go away!  */ | 
|  | if (ECOFF_IS_STAB (&sh) || (name[0] == '#')) | 
|  | { | 
|  | int type_code = ECOFF_UNMARK_STAB (sh.index); | 
|  | enum language language = PST_PRIVATE (pst)->pst_language; | 
|  |  | 
|  | /* We should never get non N_STAB symbols here, but they | 
|  | should be harmless, so keep process_one_symbol from | 
|  | complaining about them.  */ | 
|  | if (type_code & N_STAB) | 
|  | { | 
|  | /* If we found a trailing N_SO with no name, process | 
|  | it here instead of in process_one_symbol, so we | 
|  | can keep a handle to its symtab.  The symtab | 
|  | would otherwise be ended twice, once in | 
|  | process_one_symbol, and once after this loop.  */ | 
|  | if (type_code == N_SO | 
|  | && get_last_source_file () | 
|  | && previous_stab_code != (unsigned char) N_SO | 
|  | && *name == '\000') | 
|  | { | 
|  | valu += section_offsets[SECT_OFF_TEXT (objfile)]; | 
|  | previous_stab_code = N_SO; | 
|  | cust = end_compunit_symtab (valu, SECT_OFF_TEXT (objfile)); | 
|  | end_stabs (); | 
|  | last_symtab_ended = 1; | 
|  | } | 
|  | else | 
|  | { | 
|  | last_symtab_ended = 0; | 
|  | process_one_symbol (type_code, 0, valu, name, | 
|  | section_offsets, objfile, language); | 
|  | } | 
|  | } | 
|  | /* Similarly a hack.  */ | 
|  | else if (name[0] == '#') | 
|  | { | 
|  | process_one_symbol (N_SLINE, 0, valu, name, | 
|  | section_offsets, objfile, language); | 
|  | } | 
|  | if (type_code == N_FUN) | 
|  | { | 
|  | /* Make up special symbol to contain | 
|  | procedure specific info.  */ | 
|  | mdebug_extra_func_info *e | 
|  | = OBSTACK_ZALLOC (&mdebugread_objfile->objfile_obstack, | 
|  | mdebug_extra_func_info); | 
|  | struct symbol *s = new_symbol (MDEBUG_EFI_SYMBOL_NAME); | 
|  |  | 
|  | s->set_domain (LABEL_DOMAIN); | 
|  | s->set_aclass_index (LOC_CONST); | 
|  | s->set_type (objfile_type (objfile)->builtin_void); | 
|  | s->set_value_bytes ((gdb_byte *) e); | 
|  | e->pdr.framereg = -1; | 
|  | add_symbol_to_list (s, get_local_symbols ()); | 
|  | } | 
|  | } | 
|  | else if (sh.st == stLabel) | 
|  | { | 
|  | if (sh.index == indexNil) | 
|  | { | 
|  | /* This is what the gcc2_compiled and __gnu_compiled_* | 
|  | show up as.  So don't complain.  */ | 
|  | ; | 
|  | } | 
|  | else | 
|  | { | 
|  | /* Handle encoded stab line number.  */ | 
|  | valu += section_offsets[SECT_OFF_TEXT (objfile)]; | 
|  | record_line (get_current_subfile (), sh.index, | 
|  | gdbarch_addr_bits_remove (gdbarch, valu)); | 
|  | } | 
|  | } | 
|  | else if (sh.st == stProc || sh.st == stStaticProc | 
|  | || sh.st == stStatic || sh.st == stEnd) | 
|  | /* These are generated by gcc-2.x, do not complain.  */ | 
|  | ; | 
|  | else | 
|  | complaint (_("unknown stabs symbol %s"), name); | 
|  | } | 
|  |  | 
|  | if (! last_symtab_ended) | 
|  | { | 
|  | cust = end_compunit_symtab (pst->raw_text_high (), | 
|  | SECT_OFF_TEXT (objfile)); | 
|  | end_stabs (); | 
|  | } | 
|  |  | 
|  | /* There used to be a call to sort_blocks here, but this should not | 
|  | be necessary for stabs symtabs.  And as sort_blocks modifies the | 
|  | start address of the GLOBAL_BLOCK to the FIRST_LOCAL_BLOCK, | 
|  | it did the wrong thing if the first procedure in a file was | 
|  | generated via asm statements.  */ | 
|  |  | 
|  | /* Fill in procedure info next.  */ | 
|  | if (fh->cpd > 0) | 
|  | { | 
|  | char *pdr_ptr; | 
|  | char *pdr_end; | 
|  | PDR *pdr_in; | 
|  | PDR *pdr_in_end; | 
|  |  | 
|  | gdb::def_vector<PDR> pr_block (fh->cpd); | 
|  |  | 
|  | pdr_ptr = ((char *) debug_info->external_pdr | 
|  | + fh->ipdFirst * external_pdr_size); | 
|  | pdr_end = pdr_ptr + fh->cpd * external_pdr_size; | 
|  | pdr_in = pr_block.data (); | 
|  | for (; | 
|  | pdr_ptr < pdr_end; | 
|  | pdr_ptr += external_pdr_size, pdr_in++) | 
|  | { | 
|  | (*swap_pdr_in) (cur_bfd, pdr_ptr, pdr_in); | 
|  |  | 
|  | /* Determine lowest PDR address, the PDRs are not always | 
|  | sorted.  */ | 
|  | if (pdr_in == pr_block.data ()) | 
|  | lowest_pdr_addr = pdr_in->adr; | 
|  | else if (pdr_in->adr < lowest_pdr_addr) | 
|  | lowest_pdr_addr = pdr_in->adr; | 
|  | } | 
|  |  | 
|  | pdr_in = pr_block.data (); | 
|  | pdr_in_end = pdr_in + fh->cpd; | 
|  | for (; pdr_in < pdr_in_end; pdr_in++) | 
|  | parse_procedure (pdr_in, cust, pst); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | /* This symbol table contains ordinary ecoff entries.  */ | 
|  |  | 
|  | int maxlines, size; | 
|  | EXTR *ext_ptr; | 
|  |  | 
|  | if (fh == 0) | 
|  | { | 
|  | maxlines = 0; | 
|  | cust = new_symtab ("unknown", 0, objfile); | 
|  | } | 
|  | else | 
|  | { | 
|  | maxlines = 2 * fh->cline; | 
|  | cust = new_symtab (pst->filename, maxlines, objfile); | 
|  |  | 
|  | /* The proper language was already determined when building | 
|  | the psymtab, use it.  */ | 
|  | cust->primary_filetab ()->set_language | 
|  | (PST_PRIVATE (pst)->pst_language); | 
|  | } | 
|  |  | 
|  | psymtab_language = cust->primary_filetab ()->language (); | 
|  |  | 
|  | lines = cust->primary_filetab ()->linetable (); | 
|  |  | 
|  | /* Get a new lexical context.  */ | 
|  |  | 
|  | push_parse_stack (); | 
|  | top_stack->cur_st = cust->primary_filetab (); | 
|  | top_stack->cur_block | 
|  | = BLOCKVECTOR_BLOCK (cust->blockvector (), STATIC_BLOCK); | 
|  | BLOCK_START (top_stack->cur_block) = pst->text_low (objfile); | 
|  | BLOCK_END (top_stack->cur_block) = 0; | 
|  | top_stack->blocktype = stFile; | 
|  | top_stack->cur_type = 0; | 
|  | top_stack->procadr = 0; | 
|  | top_stack->numargs = 0; | 
|  | found_ecoff_debugging_info = 0; | 
|  |  | 
|  | if (fh) | 
|  | { | 
|  | char *sym_ptr; | 
|  | char *sym_end; | 
|  |  | 
|  | /* Parse local symbols first.  */ | 
|  | sym_ptr = ((char *) debug_info->external_sym | 
|  | + fh->isymBase * external_sym_size); | 
|  | sym_end = sym_ptr + fh->csym * external_sym_size; | 
|  | while (sym_ptr < sym_end) | 
|  | { | 
|  | SYMR sh; | 
|  | int c; | 
|  |  | 
|  | (*swap_sym_in) (cur_bfd, sym_ptr, &sh); | 
|  | c = parse_symbol (&sh, | 
|  | debug_info->external_aux + fh->iauxBase, | 
|  | sym_ptr, fh->fBigendian, | 
|  | section_offsets, objfile); | 
|  | sym_ptr += c * external_sym_size; | 
|  | } | 
|  |  | 
|  | /* Linenumbers.  At the end, check if we can save memory. | 
|  | parse_lines has to look ahead an arbitrary number of PDR | 
|  | structures, so we swap them all first.  */ | 
|  | if (fh->cpd > 0) | 
|  | { | 
|  | char *pdr_ptr; | 
|  | char *pdr_end; | 
|  | PDR *pdr_in; | 
|  | PDR *pdr_in_end; | 
|  |  | 
|  | gdb::def_vector<PDR> pr_block (fh->cpd); | 
|  |  | 
|  | pdr_ptr = ((char *) debug_info->external_pdr | 
|  | + fh->ipdFirst * external_pdr_size); | 
|  | pdr_end = pdr_ptr + fh->cpd * external_pdr_size; | 
|  | pdr_in = pr_block.data (); | 
|  | for (; | 
|  | pdr_ptr < pdr_end; | 
|  | pdr_ptr += external_pdr_size, pdr_in++) | 
|  | { | 
|  | (*swap_pdr_in) (cur_bfd, pdr_ptr, pdr_in); | 
|  |  | 
|  | /* Determine lowest PDR address, the PDRs are not always | 
|  | sorted.  */ | 
|  | if (pdr_in == pr_block.data ()) | 
|  | lowest_pdr_addr = pdr_in->adr; | 
|  | else if (pdr_in->adr < lowest_pdr_addr) | 
|  | lowest_pdr_addr = pdr_in->adr; | 
|  | } | 
|  |  | 
|  | parse_lines (fh, pr_block.data (), lines, maxlines, | 
|  | pst->text_low (objfile), lowest_pdr_addr); | 
|  | if (lines->nitems < fh->cline) | 
|  | lines = shrink_linetable (lines); | 
|  |  | 
|  | /* Fill in procedure info next.  */ | 
|  | pdr_in = pr_block.data (); | 
|  | pdr_in_end = pdr_in + fh->cpd; | 
|  | for (; pdr_in < pdr_in_end; pdr_in++) | 
|  | parse_procedure (pdr_in, NULL, pst); | 
|  | } | 
|  | } | 
|  |  | 
|  | size = lines->nitems; | 
|  | if (size > 1) | 
|  | --size; | 
|  | cust->primary_filetab ()->set_linetable | 
|  | ((struct linetable *) | 
|  | obstack_copy (&mdebugread_objfile->objfile_obstack, | 
|  | lines, (sizeof (struct linetable) | 
|  | + size * sizeof (lines->item)))); | 
|  | xfree (lines); | 
|  |  | 
|  | /* .. and our share of externals. | 
|  | XXX use the global list to speed up things here.  How? | 
|  | FIXME, Maybe quit once we have found the right number of ext's?  */ | 
|  | top_stack->cur_st = cust->primary_filetab (); | 
|  | top_stack->cur_block | 
|  | = BLOCKVECTOR_BLOCK (top_stack->cur_st->compunit ()->blockvector (), | 
|  | GLOBAL_BLOCK); | 
|  | top_stack->blocktype = stFile; | 
|  |  | 
|  | ext_ptr = PST_PRIVATE (pst)->extern_tab; | 
|  | for (i = PST_PRIVATE (pst)->extern_count; --i >= 0; ext_ptr++) | 
|  | parse_external (ext_ptr, fh->fBigendian, | 
|  | section_offsets, objfile); | 
|  |  | 
|  | /* If there are undefined symbols, tell the user. | 
|  | The alpha has an undefined symbol for every symbol that is | 
|  | from a shared library, so tell the user only if verbose is on.  */ | 
|  | if (info_verbose && n_undef_symbols) | 
|  | { | 
|  | gdb_printf (_("File %s contains %d unresolved references:"), | 
|  | symtab_to_filename_for_display | 
|  | (cust->primary_filetab ()), | 
|  | n_undef_symbols); | 
|  | gdb_printf ("\n\t%4d variables\n\t%4d " | 
|  | "procedures\n\t%4d labels\n", | 
|  | n_undef_vars, n_undef_procs, n_undef_labels); | 
|  | n_undef_symbols = n_undef_labels = n_undef_vars = n_undef_procs = 0; | 
|  |  | 
|  | } | 
|  | pop_parse_stack (); | 
|  |  | 
|  | sort_blocks (cust->primary_filetab ()); | 
|  | } | 
|  |  | 
|  | /* Now link the psymtab and the symtab.  */ | 
|  | pst->compunit_symtab = cust; | 
|  |  | 
|  | mdebugread_objfile = NULL; | 
|  | } | 
|  |  | 
|  | /* Ancillary parsing procedures.  */ | 
|  |  | 
|  | /* Return 1 if the symbol pointed to by SH has a cross reference | 
|  | to an opaque aggregate type, else 0.  */ | 
|  |  | 
|  | static int | 
|  | has_opaque_xref (FDR *fh, SYMR *sh) | 
|  | { | 
|  | TIR tir; | 
|  | union aux_ext *ax; | 
|  | RNDXR rn[1]; | 
|  | unsigned int rf; | 
|  |  | 
|  | if (sh->index == indexNil) | 
|  | return 0; | 
|  |  | 
|  | ax = debug_info->external_aux + fh->iauxBase + sh->index; | 
|  | (*debug_swap->swap_tir_in) (fh->fBigendian, &ax->a_ti, &tir); | 
|  | if (tir.bt != btStruct && tir.bt != btUnion && tir.bt != btEnum) | 
|  | return 0; | 
|  |  | 
|  | ax++; | 
|  | (*debug_swap->swap_rndx_in) (fh->fBigendian, &ax->a_rndx, rn); | 
|  | if (rn->rfd == 0xfff) | 
|  | rf = AUX_GET_ISYM (fh->fBigendian, ax + 1); | 
|  | else | 
|  | rf = rn->rfd; | 
|  | if (rf != -1) | 
|  | return 0; | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | /* Lookup the type at relative index RN.  Return it in TPP | 
|  | if found and in any event come up with its name PNAME. | 
|  | BIGEND says whether aux symbols are big-endian or not (from fh->fBigendian). | 
|  | Return value says how many aux symbols we ate.  */ | 
|  |  | 
|  | static int | 
|  | cross_ref (int fd, union aux_ext *ax, struct type **tpp, | 
|  | enum type_code type_code, | 
|  | /* Use to alloc new type if none is found.  */ | 
|  | const char **pname, int bigend, const char *sym_name) | 
|  | { | 
|  | RNDXR rn[1]; | 
|  | unsigned int rf; | 
|  | int result = 1; | 
|  | FDR *fh; | 
|  | char *esh; | 
|  | SYMR sh; | 
|  | int xref_fd; | 
|  | struct mdebug_pending *pend; | 
|  |  | 
|  | *tpp = NULL; | 
|  |  | 
|  | (*debug_swap->swap_rndx_in) (bigend, &ax->a_rndx, rn); | 
|  |  | 
|  | /* Escape index means 'the next one'.  */ | 
|  | if (rn->rfd == 0xfff) | 
|  | { | 
|  | result++; | 
|  | rf = AUX_GET_ISYM (bigend, ax + 1); | 
|  | } | 
|  | else | 
|  | { | 
|  | rf = rn->rfd; | 
|  | } | 
|  |  | 
|  | /* mips cc uses a rf of -1 for opaque struct definitions. | 
|  | Set TYPE_STUB for these types so that check_typedef will | 
|  | resolve them if the struct gets defined in another compilation unit.  */ | 
|  | if (rf == -1) | 
|  | { | 
|  | *pname = "<undefined>"; | 
|  | *tpp = init_type (mdebugread_objfile, type_code, 0, NULL); | 
|  | (*tpp)->set_is_stub (true); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | /* mips cc uses an escaped rn->index of 0 for struct return types | 
|  | of procedures that were compiled without -g.  These will always remain | 
|  | undefined.  */ | 
|  | if (rn->rfd == 0xfff && rn->index == 0) | 
|  | { | 
|  | *pname = "<undefined>"; | 
|  | return result; | 
|  | } | 
|  |  | 
|  | /* Find the relative file descriptor and the symbol in it.  */ | 
|  | fh = get_rfd (fd, rf); | 
|  | xref_fd = fh - debug_info->fdr; | 
|  |  | 
|  | if (rn->index >= fh->csym) | 
|  | { | 
|  | /* File indirect entry is corrupt.  */ | 
|  | *pname = "<illegal>"; | 
|  | bad_rfd_entry_complaint (sym_name, xref_fd, rn->index); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | /* If we have processed this symbol then we left a forwarding | 
|  | pointer to the type in the pending list.  If not, we`ll put | 
|  | it in a list of pending types, to be processed later when | 
|  | the file will be.  In any event, we collect the name for the | 
|  | type here.  */ | 
|  |  | 
|  | esh = ((char *) debug_info->external_sym | 
|  | + ((fh->isymBase + rn->index) | 
|  | * debug_swap->external_sym_size)); | 
|  | (*debug_swap->swap_sym_in) (cur_bfd, esh, &sh); | 
|  |  | 
|  | /* Make sure that this type of cross reference can be handled.  */ | 
|  | if ((sh.sc != scInfo | 
|  | || (sh.st != stBlock && sh.st != stTypedef && sh.st != stIndirect | 
|  | && sh.st != stStruct && sh.st != stUnion | 
|  | && sh.st != stEnum)) | 
|  | && (sh.st != stBlock || !SC_IS_COMMON (sh.sc))) | 
|  | { | 
|  | /* File indirect entry is corrupt.  */ | 
|  | *pname = "<illegal>"; | 
|  | bad_rfd_entry_complaint (sym_name, xref_fd, rn->index); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | *pname = debug_info->ss + fh->issBase + sh.iss; | 
|  |  | 
|  | pend = is_pending_symbol (fh, esh); | 
|  | if (pend) | 
|  | *tpp = pend->t; | 
|  | else | 
|  | { | 
|  | /* We have not yet seen this type.  */ | 
|  |  | 
|  | if ((sh.iss == 0 && sh.st == stTypedef) || sh.st == stIndirect) | 
|  | { | 
|  | TIR tir; | 
|  |  | 
|  | /* alpha cc puts out a stTypedef with a sh.iss of zero for | 
|  | two cases: | 
|  | a) forward declarations of structs/unions/enums which are not | 
|  | defined in this compilation unit. | 
|  | For these the type will be void.  This is a bad design decision | 
|  | as cross referencing across compilation units is impossible | 
|  | due to the missing name. | 
|  | b) forward declarations of structs/unions/enums/typedefs which | 
|  | are defined later in this file or in another file in the same | 
|  | compilation unit.  Irix5 cc uses a stIndirect symbol for this. | 
|  | Simply cross reference those again to get the true type. | 
|  | The forward references are not entered in the pending list and | 
|  | in the symbol table.  */ | 
|  |  | 
|  | (*debug_swap->swap_tir_in) (bigend, | 
|  | &(debug_info->external_aux | 
|  | + fh->iauxBase + sh.index)->a_ti, | 
|  | &tir); | 
|  | if (tir.tq0 != tqNil) | 
|  | complaint (_("illegal tq0 in forward typedef for %s"), sym_name); | 
|  | switch (tir.bt) | 
|  | { | 
|  | case btVoid: | 
|  | *tpp = init_type (mdebugread_objfile, type_code, 0, NULL); | 
|  | *pname = "<undefined>"; | 
|  | break; | 
|  |  | 
|  | case btStruct: | 
|  | case btUnion: | 
|  | case btEnum: | 
|  | cross_ref (xref_fd, | 
|  | (debug_info->external_aux | 
|  | + fh->iauxBase + sh.index + 1), | 
|  | tpp, type_code, pname, | 
|  | fh->fBigendian, sym_name); | 
|  | break; | 
|  |  | 
|  | case btTypedef: | 
|  | /* Follow a forward typedef.  This might recursively | 
|  | call cross_ref till we get a non typedef'ed type. | 
|  | FIXME: This is not correct behaviour, but gdb currently | 
|  | cannot handle typedefs without type copying.  Type | 
|  | copying is impossible as we might have mutual forward | 
|  | references between two files and the copied type would not | 
|  | get filled in when we later parse its definition.  */ | 
|  | *tpp = parse_type (xref_fd, | 
|  | debug_info->external_aux + fh->iauxBase, | 
|  | sh.index, | 
|  | NULL, | 
|  | fh->fBigendian, | 
|  | debug_info->ss + fh->issBase + sh.iss); | 
|  | add_pending (fh, esh, *tpp); | 
|  | break; | 
|  |  | 
|  | default: | 
|  | complaint (_("illegal bt %d in forward typedef for %s"), tir.bt, | 
|  | sym_name); | 
|  | *tpp = init_type (mdebugread_objfile, type_code, 0, NULL); | 
|  | break; | 
|  | } | 
|  | return result; | 
|  | } | 
|  | else if (sh.st == stTypedef) | 
|  | { | 
|  | /* Parse the type for a normal typedef.  This might recursively call | 
|  | cross_ref till we get a non typedef'ed type. | 
|  | FIXME: This is not correct behaviour, but gdb currently | 
|  | cannot handle typedefs without type copying.  But type copying is | 
|  | impossible as we might have mutual forward references between | 
|  | two files and the copied type would not get filled in when | 
|  | we later parse its definition.   */ | 
|  | *tpp = parse_type (xref_fd, | 
|  | debug_info->external_aux + fh->iauxBase, | 
|  | sh.index, | 
|  | NULL, | 
|  | fh->fBigendian, | 
|  | debug_info->ss + fh->issBase + sh.iss); | 
|  | } | 
|  | else | 
|  | { | 
|  | /* Cross reference to a struct/union/enum which is defined | 
|  | in another file in the same compilation unit but that file | 
|  | has not been parsed yet. | 
|  | Initialize the type only, it will be filled in when | 
|  | it's definition is parsed.  */ | 
|  | *tpp = init_type (mdebugread_objfile, type_code, 0, NULL); | 
|  | } | 
|  | add_pending (fh, esh, *tpp); | 
|  | } | 
|  |  | 
|  | /* We used one auxent normally, two if we got a "next one" rf.  */ | 
|  | return result; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Quick&dirty lookup procedure, to avoid the MI ones that require | 
|  | keeping the symtab sorted.  */ | 
|  |  | 
|  | static struct symbol * | 
|  | mylookup_symbol (const char *name, const struct block *block, | 
|  | domain_enum domain, enum address_class theclass) | 
|  | { | 
|  | struct block_iterator iter; | 
|  | int inc; | 
|  | struct symbol *sym; | 
|  |  | 
|  | inc = name[0]; | 
|  | ALL_BLOCK_SYMBOLS (block, iter, sym) | 
|  | { | 
|  | if (sym->linkage_name ()[0] == inc | 
|  | && sym->domain () == domain | 
|  | && sym->aclass () == theclass | 
|  | && strcmp (sym->linkage_name (), name) == 0) | 
|  | return sym; | 
|  | } | 
|  |  | 
|  | block = BLOCK_SUPERBLOCK (block); | 
|  | if (block) | 
|  | return mylookup_symbol (name, block, domain, theclass); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Add a new symbol S to a block B.  */ | 
|  |  | 
|  | static void | 
|  | add_symbol (struct symbol *s, struct symtab *symtab, struct block *b) | 
|  | { | 
|  | symbol_set_symtab (s, symtab); | 
|  | mdict_add_symbol (BLOCK_MULTIDICT (b), s); | 
|  | } | 
|  |  | 
|  | /* Add a new block B to a symtab S.  */ | 
|  |  | 
|  | static void | 
|  | add_block (struct block *b, struct symtab *s) | 
|  | { | 
|  | /* Cast away "const", but that's ok because we're building the | 
|  | symtab and blockvector here.  */ | 
|  | struct blockvector *bv | 
|  | = (struct blockvector *) s->compunit ()->blockvector (); | 
|  |  | 
|  | bv = (struct blockvector *) xrealloc ((void *) bv, | 
|  | (sizeof (struct blockvector) | 
|  | + BLOCKVECTOR_NBLOCKS (bv) | 
|  | * sizeof (bv->block))); | 
|  | if (bv != s->compunit ()->blockvector ()) | 
|  | s->compunit ()->set_blockvector (bv); | 
|  |  | 
|  | BLOCKVECTOR_BLOCK (bv, BLOCKVECTOR_NBLOCKS (bv)++) = b; | 
|  | } | 
|  |  | 
|  | /* Add a new linenumber entry (LINENO,ADR) to a linevector LT. | 
|  | MIPS' linenumber encoding might need more than one byte | 
|  | to describe it, LAST is used to detect these continuation lines. | 
|  |  | 
|  | Combining lines with the same line number seems like a bad idea. | 
|  | E.g: There could be a line number entry with the same line number after the | 
|  | prologue and GDB should not ignore it (this is a better way to find | 
|  | a prologue than mips_skip_prologue). | 
|  | But due to the compressed line table format there are line number entries | 
|  | for the same line which are needed to bridge the gap to the next | 
|  | line number entry.  These entries have a bogus address info with them | 
|  | and we are unable to tell them from intended duplicate line number | 
|  | entries. | 
|  | This is another reason why -ggdb debugging format is preferable.  */ | 
|  |  | 
|  | static int | 
|  | add_line (struct linetable *lt, int lineno, CORE_ADDR adr, int last) | 
|  | { | 
|  | /* DEC c89 sometimes produces zero linenos which confuse gdb. | 
|  | Change them to something sensible.  */ | 
|  | if (lineno == 0) | 
|  | lineno = 1; | 
|  | if (last == 0) | 
|  | last = -2;			/* Make sure we record first line.  */ | 
|  |  | 
|  | if (last == lineno)		/* Skip continuation lines.  */ | 
|  | return lineno; | 
|  |  | 
|  | lt->item[lt->nitems].line = lineno; | 
|  | lt->item[lt->nitems++].pc = adr << 2; | 
|  | return lineno; | 
|  | } | 
|  |  | 
|  | /* Sorting and reordering procedures.  */ | 
|  |  | 
|  | /* Blocks with a smaller low bound should come first.  */ | 
|  |  | 
|  | static bool | 
|  | block_is_less_than (const struct block *b1, const struct block *b2) | 
|  | { | 
|  | CORE_ADDR start1 = BLOCK_START (b1); | 
|  | CORE_ADDR start2 = BLOCK_START (b2); | 
|  |  | 
|  | if (start1 != start2) | 
|  | return start1 < start2; | 
|  |  | 
|  | return (BLOCK_END (b2)) < (BLOCK_END (b1)); | 
|  | } | 
|  |  | 
|  | /* Sort the blocks of a symtab S. | 
|  | Reorder the blocks in the blockvector by code-address, | 
|  | as required by some MI search routines.  */ | 
|  |  | 
|  | static void | 
|  | sort_blocks (struct symtab *s) | 
|  | { | 
|  | /* We have to cast away const here, but this is ok because we're | 
|  | constructing the blockvector in this code.  */ | 
|  | struct blockvector *bv | 
|  | = (struct blockvector *) s->compunit ()->blockvector (); | 
|  |  | 
|  | if (BLOCKVECTOR_NBLOCKS (bv) <= FIRST_LOCAL_BLOCK) | 
|  | { | 
|  | /* Cosmetic */ | 
|  | if (BLOCK_END (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)) == 0) | 
|  | BLOCK_START (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)) = 0; | 
|  | if (BLOCK_END (BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)) == 0) | 
|  | BLOCK_START (BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)) = 0; | 
|  | return; | 
|  | } | 
|  | /* | 
|  | * This is very unfortunate: normally all functions are compiled in | 
|  | * the order they are found, but if the file is compiled -O3 things | 
|  | * are very different.  It would be nice to find a reliable test | 
|  | * to detect -O3 images in advance. | 
|  | */ | 
|  | if (BLOCKVECTOR_NBLOCKS (bv) > FIRST_LOCAL_BLOCK + 1) | 
|  | std::sort (&BLOCKVECTOR_BLOCK (bv, FIRST_LOCAL_BLOCK), | 
|  | &BLOCKVECTOR_BLOCK (bv, BLOCKVECTOR_NBLOCKS (bv)), | 
|  | block_is_less_than); | 
|  |  | 
|  | { | 
|  | CORE_ADDR high = 0; | 
|  | int i, j = BLOCKVECTOR_NBLOCKS (bv); | 
|  |  | 
|  | for (i = FIRST_LOCAL_BLOCK; i < j; i++) | 
|  | if (high < BLOCK_END (BLOCKVECTOR_BLOCK (bv, i))) | 
|  | high = BLOCK_END (BLOCKVECTOR_BLOCK (bv, i)); | 
|  | BLOCK_END (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)) = high; | 
|  | } | 
|  |  | 
|  | BLOCK_START (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)) = | 
|  | BLOCK_START (BLOCKVECTOR_BLOCK (bv, FIRST_LOCAL_BLOCK)); | 
|  |  | 
|  | BLOCK_START (BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)) = | 
|  | BLOCK_START (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)); | 
|  | BLOCK_END (BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)) = | 
|  | BLOCK_END (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Constructor/restructor/destructor procedures.  */ | 
|  |  | 
|  | /* Allocate a new symtab for NAME.  Needs an estimate of how many | 
|  | linenumbers MAXLINES we'll put in it.  */ | 
|  |  | 
|  | static struct compunit_symtab * | 
|  | new_symtab (const char *name, int maxlines, struct objfile *objfile) | 
|  | { | 
|  | struct compunit_symtab *cust = allocate_compunit_symtab (objfile, name); | 
|  | struct symtab *symtab; | 
|  | struct blockvector *bv; | 
|  | enum language lang; | 
|  |  | 
|  | add_compunit_symtab_to_objfile (cust); | 
|  | symtab = allocate_symtab (cust, name); | 
|  |  | 
|  | symtab->set_linetable (new_linetable (maxlines)); | 
|  | lang = compunit_language (cust); | 
|  |  | 
|  | /* All symtabs must have at least two blocks.  */ | 
|  | bv = new_bvect (2); | 
|  | BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK) = new_block (NON_FUNCTION_BLOCK, lang); | 
|  | BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK) = new_block (NON_FUNCTION_BLOCK, lang); | 
|  | BLOCK_SUPERBLOCK (BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)) = | 
|  | BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); | 
|  | cust->set_blockvector (bv); | 
|  |  | 
|  | cust->set_debugformat ("ECOFF"); | 
|  | return cust; | 
|  | } | 
|  |  | 
|  | /* Allocate a new partial_symtab NAME.  */ | 
|  |  | 
|  | static legacy_psymtab * | 
|  | new_psymtab (const char *name, psymtab_storage *partial_symtabs, | 
|  | struct objfile *objfile) | 
|  | { | 
|  | legacy_psymtab *psymtab; | 
|  |  | 
|  | psymtab = new legacy_psymtab (name, partial_symtabs, objfile->per_bfd); | 
|  |  | 
|  | /* Keep a backpointer to the file's symbols.  */ | 
|  |  | 
|  | psymtab->read_symtab_private | 
|  | = OBSTACK_ZALLOC (&objfile->objfile_obstack, symloc); | 
|  | CUR_BFD (psymtab) = cur_bfd; | 
|  | DEBUG_SWAP (psymtab) = debug_swap; | 
|  | DEBUG_INFO (psymtab) = debug_info; | 
|  | PENDING_LIST (psymtab) = pending_list; | 
|  |  | 
|  | /* The way to turn this into a symtab is to call...  */ | 
|  | psymtab->legacy_read_symtab = mdebug_read_symtab; | 
|  | psymtab->legacy_expand_psymtab = mdebug_expand_psymtab; | 
|  | return (psymtab); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Allocate a linetable array of the given SIZE.  Since the struct | 
|  | already includes one item, we subtract one when calculating the | 
|  | proper size to allocate.  */ | 
|  |  | 
|  | static struct linetable * | 
|  | new_linetable (int size) | 
|  | { | 
|  | struct linetable *l; | 
|  |  | 
|  | if (size > 1) | 
|  | --size; | 
|  | size = size * sizeof (l->item) + sizeof (struct linetable); | 
|  | l = (struct linetable *) xmalloc (size); | 
|  | l->nitems = 0; | 
|  | return l; | 
|  | } | 
|  |  | 
|  | /* Oops, too big.  Shrink it.  This was important with the 2.4 linetables, | 
|  | I am not so sure about the 3.4 ones. | 
|  |  | 
|  | Since the struct linetable already includes one item, we subtract one when | 
|  | calculating the proper size to allocate.  */ | 
|  |  | 
|  | static struct linetable * | 
|  | shrink_linetable (struct linetable *lt) | 
|  | { | 
|  | return (struct linetable *) xrealloc ((void *) lt, | 
|  | (sizeof (struct linetable) | 
|  | + ((lt->nitems - 1) | 
|  | * sizeof (lt->item)))); | 
|  | } | 
|  |  | 
|  | /* Allocate and zero a new blockvector of NBLOCKS blocks.  */ | 
|  |  | 
|  | static struct blockvector * | 
|  | new_bvect (int nblocks) | 
|  | { | 
|  | struct blockvector *bv; | 
|  | int size; | 
|  |  | 
|  | size = sizeof (struct blockvector) + nblocks * sizeof (struct block *); | 
|  | bv = (struct blockvector *) xzalloc (size); | 
|  |  | 
|  | BLOCKVECTOR_NBLOCKS (bv) = nblocks; | 
|  |  | 
|  | return bv; | 
|  | } | 
|  |  | 
|  | /* Allocate and zero a new block of language LANGUAGE, and set its | 
|  | BLOCK_MULTIDICT.  If function is non-zero, assume the block is | 
|  | associated to a function, and make sure that the symbols are stored | 
|  | linearly; otherwise, store them hashed.  */ | 
|  |  | 
|  | static struct block * | 
|  | new_block (enum block_type type, enum language language) | 
|  | { | 
|  | /* FIXME: carlton/2003-09-11: This should use allocate_block to | 
|  | allocate the block.  Which, in turn, suggests that the block | 
|  | should be allocated on an obstack.  */ | 
|  | struct block *retval = XCNEW (struct block); | 
|  |  | 
|  | if (type == FUNCTION_BLOCK) | 
|  | BLOCK_MULTIDICT (retval) = mdict_create_linear_expandable (language); | 
|  | else | 
|  | BLOCK_MULTIDICT (retval) = mdict_create_hashed_expandable (language); | 
|  |  | 
|  | return retval; | 
|  | } | 
|  |  | 
|  | /* Create a new symbol with printname NAME.  */ | 
|  |  | 
|  | static struct symbol * | 
|  | new_symbol (const char *name) | 
|  | { | 
|  | struct symbol *s = new (&mdebugread_objfile->objfile_obstack) symbol; | 
|  |  | 
|  | s->set_language (psymtab_language, &mdebugread_objfile->objfile_obstack); | 
|  | s->compute_and_set_names (name, true, mdebugread_objfile->per_bfd); | 
|  | return s; | 
|  | } | 
|  |  | 
|  | /* Create a new type with printname NAME.  */ | 
|  |  | 
|  | static struct type * | 
|  | new_type (char *name) | 
|  | { | 
|  | struct type *t; | 
|  |  | 
|  | t = alloc_type (mdebugread_objfile); | 
|  | t->set_name (name); | 
|  | INIT_CPLUS_SPECIFIC (t); | 
|  | return t; | 
|  | } | 
|  |  | 
|  | /* Read ECOFF debugging information from a BFD section.  This is | 
|  | called from elfread.c.  It parses the section into a | 
|  | ecoff_debug_info struct, and then lets the rest of the file handle | 
|  | it as normal.  */ | 
|  |  | 
|  | void | 
|  | elfmdebug_build_psymtabs (struct objfile *objfile, | 
|  | const struct ecoff_debug_swap *swap, asection *sec) | 
|  | { | 
|  | bfd *abfd = objfile->obfd; | 
|  | struct ecoff_debug_info *info; | 
|  |  | 
|  | /* FIXME: It's not clear whether we should be getting minimal symbol | 
|  | information from .mdebug in an ELF file, or whether we will. | 
|  | Re-initialize the minimal symbol reader in case we do.  */ | 
|  |  | 
|  | minimal_symbol_reader reader (objfile); | 
|  |  | 
|  | info = XOBNEW (&objfile->objfile_obstack, ecoff_debug_info); | 
|  |  | 
|  | if (!(*swap->read_debug_info) (abfd, sec, info)) | 
|  | error (_("Error reading ECOFF debugging information: %s"), | 
|  | bfd_errmsg (bfd_get_error ())); | 
|  |  | 
|  | mdebug_build_psymtabs (reader, objfile, swap, info); | 
|  |  | 
|  | reader.install (); | 
|  | } | 
|  |  | 
|  | void _initialize_mdebugread (); | 
|  | void | 
|  | _initialize_mdebugread () | 
|  | { | 
|  | mdebug_register_index | 
|  | = register_symbol_register_impl (LOC_REGISTER, &mdebug_register_funcs); | 
|  | mdebug_regparm_index | 
|  | = register_symbol_register_impl (LOC_REGPARM_ADDR, &mdebug_register_funcs); | 
|  | } |