+scan_xcoff_symtab (struct objfile *objfile)
+{
+ CORE_ADDR toc_offset = 0; /* toc offset value in data section. */
+ char *filestring = NULL;
+
+ char *namestring;
+ int past_first_source_file = 0;
+ bfd *abfd;
+ asection *bfd_sect;
+ unsigned int nsyms;
+
+ /* Current partial symtab */
+ struct partial_symtab *pst;
+
+ /* List of current psymtab's include files */
+ char **psymtab_include_list;
+ int includes_allocated;
+ int includes_used;
+
+ /* Index within current psymtab dependency list */
+ struct partial_symtab **dependency_list;
+ int dependencies_used, dependencies_allocated;
+
+ char *sraw_symbol;
+ struct internal_syment symbol;
+ union internal_auxent main_aux[5];
+ unsigned int ssymnum;
+
+ char *last_csect_name = NULL; /* last seen csect's name and value */
+ CORE_ADDR last_csect_val = 0;
+ int last_csect_sec = 0;
+ int misc_func_recorded = 0; /* true if any misc. function */
+ int textlow_not_set = 1;
+
+ pst = (struct partial_symtab *) 0;
+
+ includes_allocated = 30;
+ includes_used = 0;
+ psymtab_include_list = (char **) alloca (includes_allocated *
+ sizeof (char *));
+
+ dependencies_allocated = 30;
+ dependencies_used = 0;
+ dependency_list =
+ (struct partial_symtab **) alloca (dependencies_allocated *
+ sizeof (struct partial_symtab *));
+
+ last_source_file = NULL;
+
+ abfd = objfile->obfd;
+
+ sraw_symbol = ((struct coff_symfile_info *) objfile->sym_private)->symtbl;
+ nsyms = ((struct coff_symfile_info *) objfile->sym_private)->symtbl_num_syms;
+ ssymnum = 0;
+ while (ssymnum < nsyms)
+ {
+ int sclass;
+ /* This is the type we pass to partial-stab.h. A less kludgy solution
+ would be to break out partial-stab.h into its various parts--shuffle
+ off the DBXREAD_ONLY stuff to dbxread.c, and make separate
+ pstab-norm.h (for most types), pstab-sol.h (for N_SOL), etc. */
+ int stype;
+
+ QUIT;
+
+ bfd_coff_swap_sym_in (abfd, sraw_symbol, &symbol);
+ sclass = symbol.n_sclass;
+
+ switch (sclass)
+ {
+ case C_EXT:
+ case C_HIDEXT:
+ {
+ /* The CSECT auxent--always the last auxent. */
+ union internal_auxent csect_aux;
+ unsigned int symnum_before = ssymnum;
+
+ swap_sym (&symbol, &main_aux[0], &namestring, &sraw_symbol,
+ &ssymnum, objfile);
+ if (symbol.n_numaux > 1)
+ {
+ bfd_coff_swap_aux_in
+ (objfile->obfd,
+ sraw_symbol - coff_data (abfd)->local_symesz,
+ symbol.n_type,
+ symbol.n_sclass,
+ symbol.n_numaux - 1,
+ symbol.n_numaux,
+ &csect_aux);
+ }
+ else
+ csect_aux = main_aux[0];
+
+ /* If symbol name starts with ".$" or "$", ignore it. */
+ if (namestring[0] == '$'
+ || (namestring[0] == '.' && namestring[1] == '$'))
+ break;
+
+ switch (csect_aux.x_csect.x_smtyp & 0x7)
+ {
+ case XTY_SD:
+ switch (csect_aux.x_csect.x_smclas)
+ {
+ case XMC_PR:
+ if (last_csect_name)
+ {
+ /* If no misc. function recorded in the last
+ seen csect, enter it as a function. This
+ will take care of functions like strcmp()
+ compiled by xlc. */
+
+ if (!misc_func_recorded)
+ {
+ RECORD_MINIMAL_SYMBOL
+ (last_csect_name, last_csect_val,
+ mst_text, last_csect_sec,
+ objfile);
+ }
+
+ if (pst != NULL)
+ {
+ /* We have to allocate one psymtab for
+ each program csect, because their text
+ sections need not be adjacent. */
+ xcoff_end_psymtab
+ (pst, psymtab_include_list, includes_used,
+ symnum_before, dependency_list,
+ dependencies_used, textlow_not_set);
+ includes_used = 0;
+ dependencies_used = 0;
+ /* Give all psymtabs for this source file the same
+ name. */
+ pst = xcoff_start_psymtab
+ (objfile,
+ filestring,
+ symnum_before,
+ objfile->global_psymbols.next,
+ objfile->static_psymbols.next);
+ }
+ }
+ /* Activate the misc_func_recorded mechanism for
+ compiler- and linker-generated CSECTs like ".strcmp"
+ and "@FIX1". */
+ if (namestring && (namestring[0] == '.'
+ || namestring[0] == '@'))
+ {
+ last_csect_name = namestring;
+ last_csect_val = symbol.n_value;
+ last_csect_sec =
+ secnum_to_section (symbol.n_scnum, objfile);
+ }
+ if (pst != NULL)
+ {
+ CORE_ADDR highval =
+ symbol.n_value + csect_aux.x_csect.x_scnlen.l;
+ if (highval > pst->texthigh)
+ pst->texthigh = highval;
+ if (pst->textlow == 0 || symbol.n_value < pst->textlow)
+ pst->textlow = symbol.n_value;
+ }
+ misc_func_recorded = 0;
+ break;
+
+ case XMC_RW:
+ /* Data variables are recorded in the minimal symbol
+ table, except for section symbols. */
+ if (*namestring != '.')
+ prim_record_minimal_symbol_and_info
+ (namestring, symbol.n_value,
+ sclass == C_HIDEXT ? mst_file_data : mst_data,
+ NULL, secnum_to_section (symbol.n_scnum, objfile),
+ NULL, objfile);
+ break;
+
+ case XMC_TC0:
+ if (toc_offset)
+ warning ("More than one XMC_TC0 symbol found.");
+ toc_offset = symbol.n_value;
+
+ /* Make TOC offset relative to start address of section. */
+ bfd_sect = secnum_to_bfd_section (symbol.n_scnum, objfile);
+ if (bfd_sect)
+ toc_offset -= bfd_section_vma (objfile->obfd, bfd_sect);
+ break;
+
+ case XMC_TC:
+ /* These symbols tell us where the TOC entry for a
+ variable is, not the variable itself. */
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case XTY_LD:
+ switch (csect_aux.x_csect.x_smclas)
+ {
+ case XMC_PR:
+ /* A function entry point. */
+
+ if (first_fun_line_offset == 0 && symbol.n_numaux > 1)
+ first_fun_line_offset =
+ main_aux[0].x_sym.x_fcnary.x_fcn.x_lnnoptr;
+ RECORD_MINIMAL_SYMBOL
+ (namestring, symbol.n_value,
+ sclass == C_HIDEXT ? mst_file_text : mst_text,
+ secnum_to_section (symbol.n_scnum, objfile),
+ objfile);
+ break;
+
+ case XMC_GL:
+ /* shared library function trampoline code entry
+ point. */
+
+ /* record trampoline code entries as
+ mst_solib_trampoline symbol. When we lookup mst
+ symbols, we will choose mst_text over
+ mst_solib_trampoline. */
+ RECORD_MINIMAL_SYMBOL
+ (namestring, symbol.n_value,
+ mst_solib_trampoline,
+ secnum_to_section (symbol.n_scnum, objfile),
+ objfile);
+ break;
+
+ case XMC_DS:
+ /* The symbols often have the same names as
+ debug symbols for functions, and confuse
+ lookup_symbol. */
+ break;
+
+ default:
+
+ /* xlc puts each variable in a separate csect,
+ so we get an XTY_SD for each variable. But
+ gcc puts several variables in a csect, so
+ that each variable only gets an XTY_LD. We
+ still need to record them. This will
+ typically be XMC_RW; I suspect XMC_RO and
+ XMC_BS might be possible too. */
+ if (*namestring != '.')
+ prim_record_minimal_symbol_and_info
+ (namestring, symbol.n_value,
+ sclass == C_HIDEXT ? mst_file_data : mst_data,
+ NULL, secnum_to_section (symbol.n_scnum, objfile),
+ NULL, objfile);
+ break;
+ }
+ break;
+
+ case XTY_CM:
+ switch (csect_aux.x_csect.x_smclas)
+ {
+ case XMC_RW:
+ case XMC_BS:
+ /* Common variables are recorded in the minimal symbol
+ table, except for section symbols. */
+ if (*namestring != '.')
+ prim_record_minimal_symbol_and_info
+ (namestring, symbol.n_value,
+ sclass == C_HIDEXT ? mst_file_bss : mst_bss,
+ NULL, secnum_to_section (symbol.n_scnum, objfile),
+ NULL, objfile);
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+ case C_FILE:
+ {
+ unsigned int symnum_before;
+
+ symnum_before = ssymnum;
+ swap_sym (&symbol, &main_aux[0], &namestring, &sraw_symbol,
+ &ssymnum, objfile);
+
+ /* See if the last csect needs to be recorded. */
+
+ if (last_csect_name && !misc_func_recorded)
+ {
+
+ /* If no misc. function recorded in the last seen csect, enter
+ it as a function. This will take care of functions like
+ strcmp() compiled by xlc. */
+
+ RECORD_MINIMAL_SYMBOL
+ (last_csect_name, last_csect_val,
+ mst_text, last_csect_sec, objfile);
+ }
+
+ if (pst)
+ {
+ xcoff_end_psymtab (pst, psymtab_include_list, includes_used,
+ symnum_before, dependency_list,
+ dependencies_used, textlow_not_set);
+ includes_used = 0;
+ dependencies_used = 0;
+ }
+ first_fun_line_offset = 0;
+
+ /* XCOFF, according to the AIX 3.2 documentation, puts the
+ filename in cs->c_name. But xlc 1.3.0.2 has decided to
+ do things the standard COFF way and put it in the auxent.
+ We use the auxent if the symbol is ".file" and an auxent
+ exists, otherwise use the symbol itself. */
+ if (!strcmp (namestring, ".file") && symbol.n_numaux > 0)
+ {
+ filestring = coff_getfilename (&main_aux[0], objfile);
+ }
+ else
+ filestring = namestring;
+
+ pst = xcoff_start_psymtab (objfile,
+ filestring,
+ symnum_before,
+ objfile->global_psymbols.next,
+ objfile->static_psymbols.next);
+ last_csect_name = NULL;
+ }
+ break;
+
+ default:
+ {
+ static struct complaint msg =
+ {"Storage class %d not recognized during scan", 0, 0};
+ complain (&msg, sclass);
+ }
+ /* FALLTHROUGH */
+
+ /* C_FCN is .bf and .ef symbols. I think it is sufficient
+ to handle only the C_FUN and C_EXT. */
+ case C_FCN:
+
+ case C_BSTAT:
+ case C_ESTAT:
+ case C_ARG:
+ case C_REGPARM:
+ case C_REG:
+ case C_TPDEF:
+ case C_STRTAG:
+ case C_UNTAG:
+ case C_ENTAG:
+ case C_LABEL:
+ case C_NULL:
+
+ /* C_EINCL means we are switching back to the main file. But there
+ is no reason to care; the only thing we want to know about
+ includes is the names of all the included (.h) files. */
+ case C_EINCL:
+
+ case C_BLOCK:
+
+ /* I don't think C_STAT is used in xcoff; C_HIDEXT appears to be
+ used instead. */
+ case C_STAT:
+
+ /* I don't think the name of the common block (as opposed to the
+ variables within it) is something which is user visible
+ currently. */
+ case C_BCOMM:
+ case C_ECOMM:
+
+ case C_PSYM:
+ case C_RPSYM:
+
+ /* I think we can ignore C_LSYM; types on xcoff seem to use C_DECL
+ so C_LSYM would appear to be only for locals. */
+ case C_LSYM:
+
+ case C_AUTO:
+ case C_RSYM:
+ {
+ /* We probably could save a few instructions by assuming that
+ C_LSYM, C_PSYM, etc., never have auxents. */
+ int naux1 = symbol.n_numaux + 1;
+ ssymnum += naux1;
+ sraw_symbol += bfd_coff_symesz (abfd) * naux1;
+ }
+ break;
+
+ case C_BINCL:
+ stype = N_SOL;
+ goto pstab;
+
+ case C_FUN:
+ /* The value of the C_FUN is not the address of the function (it
+ appears to be the address before linking), but as long as it
+ is smaller than the actual address, then find_pc_partial_function
+ will use the minimal symbols instead. I hope. */
+
+ case C_GSYM:
+ case C_ECOML:
+ case C_DECL:
+ case C_STSYM:
+ stype = N_LSYM;
+ pstab:
+ swap_sym (&symbol, &main_aux[0], &namestring, &sraw_symbol,
+ &ssymnum, objfile);
+#define CUR_SYMBOL_TYPE stype
+#define CUR_SYMBOL_VALUE symbol.n_value
+
+/* START_PSYMTAB and END_PSYMTAB are never used, because they are only
+ called from DBXREAD_ONLY or N_SO code. Likewise for the symnum
+ variable. */
+#define START_PSYMTAB(ofile,fname,low,symoff,global_syms,static_syms) 0
+#define END_PSYMTAB(pst,ilist,ninc,c_off,c_text,dep_list,n_deps,textlow_not_set)\
+ do {} while (0)
+/* We have already set the namestring. */
+#define SET_NAMESTRING() /* */
+
+#include "partial-stab.h"
+ }
+ }
+
+ if (pst)
+ {
+ xcoff_end_psymtab (pst, psymtab_include_list, includes_used,
+ ssymnum, dependency_list,
+ dependencies_used, textlow_not_set);
+ }
+
+ /* Record the toc offset value of this symbol table into objfile structure.
+ If no XMC_TC0 is found, toc_offset should be zero. Another place to obtain
+ this information would be file auxiliary header. */
+
+ ((struct coff_symfile_info *) objfile->sym_private)->toc_offset = toc_offset;
+}
+
+/* Return the toc offset value for a given objfile. */
+
+CORE_ADDR
+get_toc_offset (struct objfile *objfile)