| /* coffgrok.c | 
 |    Copyright (C) 1994-2022 Free Software Foundation, Inc. | 
 |  | 
 |    This file is part of GNU Binutils. | 
 |  | 
 |    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, write to the Free Software | 
 |    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, | 
 |    MA 02110-1301, USA.  */ | 
 |  | 
 |  | 
 | /* Written by Steve Chamberlain (sac@cygnus.com) | 
 |  | 
 |    This module reads a coff file and builds a really simple type tree | 
 |    which can be read by other programs.  The first application is a | 
 |    coff->sysroff converter.  It can be tested with coffdump.c.  */ | 
 |  | 
 | #include "sysdep.h" | 
 | #include "bfd.h" | 
 | #include "libiberty.h" | 
 | #include "coff/internal.h" | 
 | #include "../bfd/libcoff.h" | 
 | #include "bucomm.h" | 
 | #include "coffgrok.h" | 
 |  | 
 | static int                      lofile = 1; | 
 |  | 
 | static struct coff_scope *      top_scope; | 
 | static struct coff_scope *      file_scope; | 
 | static struct coff_ofile *      ofile; | 
 | static struct coff_symbol *     last_function_symbol; | 
 | static struct coff_type *       last_function_type; | 
 | static struct coff_type *       last_struct; | 
 | static struct coff_type *       last_enum; | 
 | static struct coff_sfile *      cur_sfile; | 
 | static struct coff_symbol **    tindex; | 
 | static asymbol **               syms; | 
 | static long                     symcount; | 
 | static struct coff_ptr_struct * rawsyms; | 
 | static unsigned int             rawcount; | 
 | static bfd *                    abfd; | 
 |  | 
 | #define N(x) ((x)->_n._n_nptr[1]) | 
 |  | 
 | #define PTR_SIZE	4 | 
 | #define SHORT_SIZE	2 | 
 | #define INT_SIZE	4 | 
 | #define LONG_SIZE	4 | 
 | #define FLOAT_SIZE	4 | 
 | #define DOUBLE_SIZE	8 | 
 |  | 
 | #define INDEXOF(p)  ((struct coff_ptr_struct *)(p)-(rawsyms)) | 
 |  | 
 |  | 
 | static struct coff_scope * | 
 | empty_scope (void) | 
 | { | 
 |   return (struct coff_scope *) (xcalloc (sizeof (struct coff_scope), 1)); | 
 | } | 
 |  | 
 | static struct coff_symbol * | 
 | empty_symbol (void) | 
 | { | 
 |   return (struct coff_symbol *) (xcalloc (sizeof (struct coff_symbol), 1)); | 
 | } | 
 |  | 
 | static void | 
 | push_scope (int slink) | 
 | { | 
 |   struct coff_scope *n = empty_scope (); | 
 |  | 
 |   if (slink) | 
 |     { | 
 |       if (top_scope) | 
 | 	{ | 
 | 	  if (top_scope->list_tail) | 
 | 	    { | 
 | 	      top_scope->list_tail->next = n; | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      top_scope->list_head = n; | 
 | 	    } | 
 | 	  top_scope->list_tail = n; | 
 | 	} | 
 |     } | 
 |   n->parent = top_scope; | 
 |  | 
 |   top_scope = n; | 
 | } | 
 |  | 
 | static void | 
 | pop_scope (void) | 
 | { | 
 |   /* PR 17512: file: 809933ac.  */ | 
 |   if (top_scope == NULL) | 
 |     fatal (_("Out of context scope change encountered")); | 
 |   top_scope = top_scope->parent; | 
 | } | 
 |  | 
 | static void | 
 | do_sections_p1 (struct coff_ofile *head) | 
 | { | 
 |   asection *section; | 
 |   int idx; | 
 |   struct coff_section *all = (struct coff_section *) (xcalloc (abfd->section_count + 1, | 
 | 					     sizeof (struct coff_section))); | 
 |   head->nsections = abfd->section_count + 1; | 
 |   head->sections = all; | 
 |  | 
 |   for (idx = 0, section = abfd->sections; section; section = section->next, idx++) | 
 |     { | 
 |       long relsize; | 
 |       unsigned int i = section->target_index; | 
 |       arelent **relpp; | 
 |       long relcount; | 
 |  | 
 |       /* PR 17512: file: 2d6effca.  */ | 
 |       if (i > abfd->section_count) | 
 | 	fatal (_("Invalid section target index: %u"), i); | 
 |  | 
 |       relsize = bfd_get_reloc_upper_bound (abfd, section); | 
 |       if (relsize < 0) | 
 | 	bfd_fatal (bfd_get_filename (abfd)); | 
 |       if (relsize == 0) | 
 | 	continue; | 
 |       relpp = (arelent **) xmalloc (relsize); | 
 |       relcount = bfd_canonicalize_reloc (abfd, section, relpp, syms); | 
 |       if (relcount < 0) | 
 | 	bfd_fatal (bfd_get_filename (abfd)); | 
 |  | 
 |       head->sections[i].name = (char *) (section->name); | 
 |       head->sections[i].code = section->flags & SEC_CODE; | 
 |       head->sections[i].data = section->flags & SEC_DATA; | 
 |       if (strcmp (section->name, ".bss") == 0) | 
 | 	head->sections[i].data = 1; | 
 |       head->sections[i].address = section->lma; | 
 |       head->sections[i].size = bfd_section_size (section); | 
 |       head->sections[i].number = idx; | 
 |       head->sections[i].nrelocs = section->reloc_count; | 
 |       head->sections[i].relocs = | 
 | 	(struct coff_reloc *) (xcalloc (section->reloc_count, | 
 | 					sizeof (struct coff_reloc))); | 
 |       head->sections[i].bfd_section = section; | 
 |     } | 
 |   head->sections[0].name = "ABSOLUTE"; | 
 |   head->sections[0].code = 0; | 
 |   head->sections[0].data = 0; | 
 |   head->sections[0].address = 0; | 
 |   head->sections[0].size = 0; | 
 |   head->sections[0].number = 0; | 
 | } | 
 |  | 
 | static void | 
 | do_sections_p2 (struct coff_ofile *head) | 
 | { | 
 |   asection *section; | 
 |  | 
 |   for (section = abfd->sections; section; section = section->next) | 
 |     { | 
 |       unsigned int j; | 
 |  | 
 |       /* PR 17512: file: 7c1a36e8. | 
 | 	 A corrupt COFF binary might have a reloc count but no relocs. | 
 | 	 Handle this here.  */ | 
 |       if (section->relocation == NULL) | 
 | 	continue; | 
 |  | 
 |       for (j = 0; j < section->reloc_count; j++) | 
 | 	{ | 
 | 	  unsigned int idx; | 
 | 	  int i = section->target_index; | 
 | 	  struct coff_reloc *r; | 
 | 	  arelent *sr = section->relocation + j; | 
 |  | 
 | 	  if (i > head->nsections) | 
 | 	    fatal (_("Invalid section target index: %d"), i); | 
 | 	  /* PR 17512: file: db850ff4.  */ | 
 | 	  if (j >= head->sections[i].nrelocs) | 
 | 	    fatal (_("Target section has insufficient relocs")); | 
 | 	  r = head->sections[i].relocs + j; | 
 | 	  r->offset = sr->address; | 
 | 	  r->addend = sr->addend; | 
 | 	  idx = ((coff_symbol_type *) (sr->sym_ptr_ptr[0]))->native - rawsyms; | 
 | 	  if (idx >= rawcount) | 
 | 	    { | 
 | 	      if (rawcount == 0) | 
 | 		fatal (_("Symbol index %u encountered when there are no symbols"), idx); | 
 | 	      non_fatal (_("Invalid symbol index %u encountered"), idx); | 
 | 	      idx = 0; | 
 | 	    } | 
 | 	  r->symbol = tindex[idx]; | 
 | 	} | 
 |     } | 
 | } | 
 |  | 
 | static struct coff_where * | 
 | do_where (unsigned int i) | 
 | { | 
 |   struct internal_syment *sym; | 
 |   struct coff_where *where = | 
 |     (struct coff_where *) (xmalloc (sizeof (struct coff_where))); | 
 |  | 
 |   if (i >= rawcount) | 
 |     fatal ("Invalid symbol index: %d\n", i); | 
 |  | 
 |   sym = &rawsyms[i].u.syment; | 
 |   where->offset = sym->n_value; | 
 |  | 
 |   if (sym->n_scnum == -1) | 
 |     sym->n_scnum = 0; | 
 |  | 
 |   switch (sym->n_sclass) | 
 |     { | 
 |     case C_FIELD: | 
 |       where->where = coff_where_member_of_struct; | 
 |       where->offset = sym->n_value / 8; | 
 |       where->bitoffset = sym->n_value % 8; | 
 |       where->bitsize = rawsyms[i + 1].u.auxent.x_sym.x_misc.x_lnsz.x_size; | 
 |       break; | 
 |     case C_MOE: | 
 |       where->where = coff_where_member_of_enum; | 
 |       break; | 
 |     case C_MOS: | 
 |     case C_MOU: | 
 |       where->where = coff_where_member_of_struct; | 
 |       break; | 
 |     case C_AUTO: | 
 |     case C_ARG: | 
 |       where->where = coff_where_stack; | 
 |       break; | 
 |     case C_EXT: | 
 |     case C_STAT: | 
 |     case C_EXTDEF: | 
 |     case C_LABEL: | 
 |       where->where = coff_where_memory; | 
 |       /* PR 17512: file: 07a37c40.  */ | 
 |       /* PR 17512: file: 0c2eb101.  */ | 
 |       if (sym->n_scnum >= ofile->nsections || sym->n_scnum < 0) | 
 | 	{ | 
 | 	  non_fatal (_("Invalid section number (%d) encountered"), | 
 | 		     sym->n_scnum); | 
 | 	  where->section = ofile->sections; | 
 | 	} | 
 |       else | 
 | 	where->section = &ofile->sections[sym->n_scnum]; | 
 |       break; | 
 |     case C_REG: | 
 |     case C_REGPARM: | 
 |       where->where = coff_where_register; | 
 |       break; | 
 |     case C_ENTAG: | 
 |       where->where = coff_where_entag; | 
 |       break; | 
 |     case C_STRTAG: | 
 |     case C_UNTAG: | 
 |       where->where = coff_where_strtag; | 
 |       break; | 
 |     case C_TPDEF: | 
 |       where->where = coff_where_typedef; | 
 |       break; | 
 |     default: | 
 |       fatal (_("Unrecognized symbol class: %d"), sym->n_sclass); | 
 |       break; | 
 |     } | 
 |   return where; | 
 | } | 
 |  | 
 | static struct coff_line * | 
 | do_lines (int i, char *name ATTRIBUTE_UNUSED) | 
 | { | 
 |   struct coff_line *res = (struct coff_line *) xcalloc (sizeof (struct coff_line), 1); | 
 |   asection *s; | 
 |   unsigned int l; | 
 |  | 
 |   /* Find out if this function has any line numbers in the table.  */ | 
 |   for (s = abfd->sections; s; s = s->next) | 
 |     { | 
 |       /* PR 17512: file: 07a37c40. | 
 | 	 A corrupt COFF binary can have a linenumber count in the header | 
 | 	 but no line number table.  This should be reported elsewhere, but | 
 | 	 do not rely upon this.  */ | 
 |       if (s->lineno == NULL) | 
 | 	continue; | 
 |  | 
 |       for (l = 0; l < s->lineno_count; l++) | 
 | 	{ | 
 | 	  if (s->lineno[l].line_number == 0) | 
 | 	    { | 
 | 	      if (rawsyms + i == ((coff_symbol_type *) (&(s->lineno[l].u.sym[0])))->native) | 
 | 		{ | 
 | 		  /* These lines are for this function - so count them and stick them on.  */ | 
 | 		  int c = 0; | 
 | 		  /* Find the linenumber of the top of the function, since coff linenumbers | 
 | 		     are relative to the start of the function.  */ | 
 | 		  int start_line = rawsyms[i + 3].u.auxent.x_sym.x_misc.x_lnsz.x_lnno; | 
 |  | 
 | 		  l++; | 
 | 		  for (c = 0; | 
 | 		       /* PR 17512: file: c2825452.  */ | 
 | 		       l + c + 1 < s->lineno_count | 
 | 			 && s->lineno[l + c + 1].line_number; | 
 | 		       c++) | 
 | 		    ; | 
 |  | 
 | 		  /* Add two extra records, one for the prologue and one for the epilogue.  */ | 
 | 		  c += 1; | 
 | 		  res->nlines = c; | 
 | 		  res->lines = (int *) (xcalloc (sizeof (int), c)); | 
 | 		  res->addresses = (int *) (xcalloc (sizeof (int), c)); | 
 | 		  res->lines[0] = start_line; | 
 | 		  res->addresses[0] = rawsyms[i].u.syment.n_value - s->vma; | 
 | 		  for (c = 0; | 
 | 		       /* PR 17512: file: c2825452.  */ | 
 | 		       l + c + 1 < s->lineno_count | 
 | 			 && s->lineno[l + c + 1].line_number; | 
 | 		       c++) | 
 | 		    { | 
 | 		      res->lines[c + 1] = s->lineno[l + c].line_number + start_line - 1; | 
 | 		      res->addresses[c + 1] = s->lineno[l + c].u.offset; | 
 | 		    } | 
 | 		  return res; | 
 | 		} | 
 | 	    } | 
 | 	} | 
 |     } | 
 |   return res; | 
 | } | 
 |  | 
 | static struct coff_type * | 
 | do_type (unsigned int i) | 
 | { | 
 |   struct internal_syment *sym; | 
 |   union internal_auxent *aux; | 
 |   struct coff_type *res = (struct coff_type *) xmalloc (sizeof (struct coff_type)); | 
 |   int type; | 
 |   int which_dt = 0; | 
 |   int dimind = 0; | 
 |  | 
 |   if (i >= rawcount) | 
 |     fatal (_("Type entry %u does not have enough symbolic information"), i); | 
 |  | 
 |   if (!rawsyms[i].is_sym) | 
 |     fatal (_("Type entry %u does not refer to a symbol"), i); | 
 |   sym = &rawsyms[i].u.syment; | 
 |  | 
 |   if (sym->n_numaux == 0 || i >= rawcount -1 || rawsyms[i + 1].is_sym) | 
 |     aux = NULL; | 
 |   else | 
 |     aux = &rawsyms[i + 1].u.auxent; | 
 |  | 
 |   type = sym->n_type; | 
 |  | 
 |   res->type = coff_basic_type; | 
 |   res->u.basic = type & 0xf; | 
 |  | 
 |   switch (type & 0xf) | 
 |     { | 
 |     case T_NULL: | 
 |     case T_VOID: | 
 |       if (sym->n_numaux && sym->n_sclass == C_STAT) | 
 | 	{ | 
 | 	  /* This is probably a section definition.  */ | 
 | 	  res->type = coff_secdef_type; | 
 | 	  if (aux == NULL) | 
 | 	    fatal (_("Section definition needs a section length")); | 
 | 	  res->size = aux->x_scn.x_scnlen; | 
 |  | 
 | 	  /* PR 17512: file: 081c955d. | 
 | 	     Fill in the asecdef structure as well.  */ | 
 | 	  res->u.asecdef.address = 0; | 
 | 	  res->u.asecdef.size = 0; | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  if (type == 0) | 
 | 	    { | 
 | 	      /* Don't know what this is, let's make it a simple int.  */ | 
 | 	      res->size = INT_SIZE; | 
 | 	      res->u.basic = T_UINT; | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      /* Else it could be a function or pointer to void.  */ | 
 | 	      res->size = 0; | 
 | 	    } | 
 | 	} | 
 |       break; | 
 |  | 
 |     case T_UCHAR: | 
 |     case T_CHAR: | 
 |       res->size = 1; | 
 |       break; | 
 |     case T_USHORT: | 
 |     case T_SHORT: | 
 |       res->size = SHORT_SIZE; | 
 |       break; | 
 |     case T_UINT: | 
 |     case T_INT: | 
 |       res->size = INT_SIZE; | 
 |       break; | 
 |     case T_ULONG: | 
 |     case T_LONG: | 
 |       res->size = LONG_SIZE; | 
 |       break; | 
 |     case T_FLOAT: | 
 |       res->size = FLOAT_SIZE; | 
 |       break; | 
 |     case T_DOUBLE: | 
 |       res->size = DOUBLE_SIZE; | 
 |       break; | 
 |     case T_STRUCT: | 
 |     case T_UNION: | 
 |       if (sym->n_numaux) | 
 | 	{ | 
 | 	  if (aux == NULL) | 
 | 	    fatal (_("Aggregate definition needs auxiliary information")); | 
 |  | 
 | 	  if (aux->x_sym.x_tagndx.p) | 
 | 	    { | 
 | 	      unsigned int idx; | 
 |  | 
 | 	      /* PR 17512: file: e72f3988.  */ | 
 | 	      if (aux->x_sym.x_tagndx.l < 0 || aux->x_sym.x_tagndx.p < rawsyms) | 
 | 		{ | 
 | 		  non_fatal (_("Invalid tag index %#lx encountered"), aux->x_sym.x_tagndx.l); | 
 | 		  idx = 0; | 
 | 		} | 
 | 	      else | 
 | 		idx = INDEXOF (aux->x_sym.x_tagndx.p); | 
 |  | 
 | 	      if (idx >= rawcount) | 
 | 		{ | 
 | 		  if (rawcount == 0) | 
 | 		    fatal (_("Symbol index %u encountered when there are no symbols"), idx); | 
 | 		  non_fatal (_("Invalid symbol index %u encountered"), idx); | 
 | 		  idx = 0; | 
 | 		} | 
 |  | 
 | 	      /* Referring to a struct defined elsewhere.  */ | 
 | 	      res->type = coff_structref_type; | 
 | 	      res->u.astructref.ref = tindex[idx]; | 
 | 	      res->size = res->u.astructref.ref ? | 
 | 		res->u.astructref.ref->type->size : 0; | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      /* A definition of a struct.  */ | 
 | 	      last_struct = res; | 
 | 	      res->type = coff_structdef_type; | 
 | 	      res->u.astructdef.elements = empty_scope (); | 
 | 	      res->u.astructdef.idx = 0; | 
 | 	      res->u.astructdef.isstruct = (type & 0xf) == T_STRUCT; | 
 | 	      res->size = aux->x_sym.x_misc.x_lnsz.x_size; | 
 | 	    } | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  /* No auxents - it's anonymous.  */ | 
 | 	  res->type = coff_structref_type; | 
 | 	  res->u.astructref.ref = 0; | 
 | 	  res->size = 0; | 
 | 	} | 
 |       break; | 
 |     case T_ENUM: | 
 |       if (aux == NULL) | 
 | 	fatal (_("Enum definition needs auxiliary information")); | 
 |       if (aux->x_sym.x_tagndx.p) | 
 | 	{ | 
 | 	  unsigned int idx = INDEXOF (aux->x_sym.x_tagndx.p); | 
 |  | 
 | 	  /* PR 17512: file: 1ef037c7.  */ | 
 | 	  if (idx >= rawcount) | 
 | 	    fatal (_("Invalid enum symbol index %u encountered"), idx); | 
 | 	  /* Referring to a enum defined elsewhere.  */ | 
 | 	  res->type = coff_enumref_type; | 
 | 	  res->u.aenumref.ref = tindex[idx]; | 
 | 	  /* PR 17512: file: b85b67e8.  */ | 
 | 	  if (res->u.aenumref.ref) | 
 | 	    res->size = res->u.aenumref.ref->type->size; | 
 | 	  else | 
 | 	    res->size = 0; | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  /* A definition of an enum.  */ | 
 | 	  last_enum = res; | 
 | 	  res->type = coff_enumdef_type; | 
 | 	  res->u.aenumdef.elements = empty_scope (); | 
 | 	  res->size = aux->x_sym.x_misc.x_lnsz.x_size; | 
 | 	} | 
 |       break; | 
 |     case T_MOE: | 
 |       break; | 
 |     } | 
 |  | 
 |   for (which_dt = 5; which_dt >= 0; which_dt--) | 
 |     { | 
 |       switch ((type >> ((which_dt * 2) + 4)) & 0x3) | 
 | 	{ | 
 | 	case 0: | 
 | 	  break; | 
 | 	case DT_ARY: | 
 | 	  { | 
 | 	    struct coff_type *ptr = ((struct coff_type *) | 
 | 				     xmalloc (sizeof (struct coff_type))); | 
 | 	    int els; | 
 |  | 
 | 	    if (aux == NULL) | 
 | 	      fatal (_("Array definition needs auxiliary information")); | 
 | 	    els = (dimind < DIMNUM | 
 | 		   ? aux->x_sym.x_fcnary.x_ary.x_dimen[dimind] | 
 | 		   : 0); | 
 |  | 
 | 	    ++dimind; | 
 | 	    ptr->type = coff_array_type; | 
 | 	    /* PR 17512: file: ae1971e2. | 
 | 	       Check for integer overflow.  */ | 
 | 	    { | 
 | 	      long long a, z; | 
 | 	      a = els; | 
 | 	      z = res->size; | 
 | 	      a *= z; | 
 | 	      ptr->size = (int) a; | 
 | 	      if (ptr->size != a) | 
 | 		non_fatal (_("Out of range sum for els (%#x) * size (%#x)"), els, res->size); | 
 | 	    } | 
 | 	    ptr->u.array.dim = els; | 
 | 	    ptr->u.array.array_of = res; | 
 | 	    res = ptr; | 
 | 	    break; | 
 | 	  } | 
 | 	case DT_PTR: | 
 | 	  { | 
 | 	    struct coff_type *ptr = | 
 | 	      (struct coff_type *) xmalloc (sizeof (struct coff_type)); | 
 |  | 
 | 	    ptr->size = PTR_SIZE; | 
 | 	    ptr->type = coff_pointer_type; | 
 | 	    ptr->u.pointer.points_to = res; | 
 | 	    res = ptr; | 
 | 	    break; | 
 | 	  } | 
 | 	case DT_FCN: | 
 | 	  { | 
 | 	    struct coff_type *ptr | 
 | 	      = (struct coff_type *) xmalloc (sizeof (struct coff_type)); | 
 |  | 
 | 	    ptr->size = 0; | 
 | 	    ptr->type = coff_function_type; | 
 | 	    ptr->u.function.function_returns = res; | 
 | 	    ptr->u.function.parameters = empty_scope (); | 
 | 	    ptr->u.function.lines = do_lines (i, N(sym)); | 
 | 	    ptr->u.function.code = 0; | 
 | 	    last_function_type = ptr; | 
 | 	    res = ptr; | 
 | 	    break; | 
 | 	  } | 
 | 	} | 
 |     } | 
 |   return res; | 
 | } | 
 |  | 
 | static struct coff_visible * | 
 | do_visible (int i) | 
 | { | 
 |   struct internal_syment *sym = &rawsyms[i].u.syment; | 
 |   struct coff_visible *visible = | 
 |     (struct coff_visible *) (xmalloc (sizeof (struct coff_visible))); | 
 |   enum coff_vis_type t; | 
 |  | 
 |   switch (sym->n_sclass) | 
 |     { | 
 |     case C_MOS: | 
 |     case C_MOU: | 
 |     case C_FIELD: | 
 |       t = coff_vis_member_of_struct; | 
 |       break; | 
 |     case C_MOE: | 
 |       t = coff_vis_member_of_enum; | 
 |       break; | 
 |     case C_REGPARM: | 
 |       t = coff_vis_regparam; | 
 |       break; | 
 |     case C_REG: | 
 |       t = coff_vis_register; | 
 |       break; | 
 |     case C_STRTAG: | 
 |     case C_UNTAG: | 
 |     case C_ENTAG: | 
 |     case C_TPDEF: | 
 |       t = coff_vis_tag; | 
 |       break; | 
 |     case C_AUTOARG: | 
 |     case C_ARG: | 
 |       t = coff_vis_autoparam; | 
 |       break; | 
 |     case C_AUTO: | 
 |       t = coff_vis_auto; | 
 |       break; | 
 |     case C_LABEL: | 
 |     case C_STAT: | 
 |       t = coff_vis_int_def; | 
 |       break; | 
 |     case C_EXT: | 
 |       if (sym->n_scnum == N_UNDEF) | 
 | 	{ | 
 | 	  if (sym->n_value) | 
 | 	    t = coff_vis_common; | 
 | 	  else | 
 | 	    t = coff_vis_ext_ref; | 
 | 	} | 
 |       else | 
 | 	t = coff_vis_ext_def; | 
 |       break; | 
 |     default: | 
 |       fatal (_("Unrecognised symbol class: %d"), sym->n_sclass); | 
 |       break; | 
 |     } | 
 |   visible->type = t; | 
 |   return visible; | 
 | } | 
 |  | 
 | /* Define a symbol and attach to block B.  */ | 
 |  | 
 | static int | 
 | do_define (unsigned int i, struct coff_scope *b) | 
 | { | 
 |   static int symbol_index; | 
 |   struct internal_syment *sym; | 
 |   struct coff_symbol *s = empty_symbol (); | 
 |  | 
 |   if (b == NULL) | 
 |     fatal (_("ICE: do_define called without a block")); | 
 |   if (i >= rawcount) | 
 |     fatal (_("Out of range symbol index: %u"), i); | 
 |  | 
 |   sym = &rawsyms[i].u.syment; | 
 |   s->number = ++symbol_index; | 
 |   s->name = N(sym); | 
 |   s->sfile = cur_sfile; | 
 |   /* Glue onto the ofile list.  */ | 
 |   if (lofile >= 0) | 
 |     { | 
 |       if (ofile->symbol_list_tail) | 
 | 	ofile->symbol_list_tail->next_in_ofile_list = s; | 
 |       else | 
 | 	ofile->symbol_list_head = s; | 
 |       ofile->symbol_list_tail = s; | 
 |       /* And the block list.  */ | 
 |     } | 
 |   if (b->vars_tail) | 
 |     b->vars_tail->next = s; | 
 |   else | 
 |     b->vars_head = s; | 
 |  | 
 |   b->vars_tail = s; | 
 |   b->nvars++; | 
 |   s->type = do_type (i); | 
 |   s->where = do_where (i); | 
 |   s->visible = do_visible (i); | 
 |  | 
 |   tindex[i] = s; | 
 |  | 
 |   /* We remember the lowest address in each section for each source file.  */ | 
 |   if (s->where->where == coff_where_memory | 
 |       && s->type->type == coff_secdef_type) | 
 |     { | 
 |       struct coff_isection *is; | 
 |  | 
 |       /* PR 17512: file: 4676c97f.  */ | 
 |       if (cur_sfile == NULL) | 
 | 	non_fatal (_("Section referenced before any file is defined")); | 
 |       else | 
 | 	{ | 
 | 	  is = cur_sfile->section + s->where->section->number; | 
 |  | 
 | 	  if (!is->init) | 
 | 	    { | 
 | 	      is->low = s->where->offset; | 
 | 	      /* PR 17512: file: 37e7a80d. | 
 | 		 Check for integer overflow computing low + size.  */ | 
 | 	      { | 
 | 		long long a, z; | 
 |  | 
 | 		a = s->where->offset; | 
 | 		z = s->type->size; | 
 | 		a += z; | 
 | 		is->high = (int) a; | 
 | 		if (a != is->high) | 
 | 		  non_fatal (_("Out of range sum for offset (%#x) + size (%#x)"), | 
 | 			     is->low, s->type->size); | 
 | 	      } | 
 | 	      /* PR 17512: file: 37e7a80d.  */ | 
 | 	      if (is->high < s->where->offset) | 
 | 		fatal (_("Out of range type size: %u"), s->type->size); | 
 | 	      is->init = 1; | 
 | 	      is->parent = s->where->section; | 
 | 	    } | 
 | 	} | 
 |     } | 
 |  | 
 |   if (s->type->type == coff_function_type) | 
 |     last_function_symbol = s; | 
 |  | 
 |   return i + sym->n_numaux + 1; | 
 | } | 
 |  | 
 | static struct coff_ofile * | 
 | doit (void) | 
 | { | 
 |   unsigned int i; | 
 |   bool infile = false; | 
 |   struct coff_ofile *head = | 
 |     (struct coff_ofile *) xmalloc (sizeof (struct coff_ofile)); | 
 |  | 
 |   ofile = head; | 
 |   head->source_head = 0; | 
 |   head->source_tail = 0; | 
 |   head->nsources = 0; | 
 |   head->symbol_list_tail = 0; | 
 |   head->symbol_list_head = 0; | 
 |   do_sections_p1 (head); | 
 |   push_scope (1); | 
 |  | 
 |   for (i = 0; i < rawcount;) | 
 |     { | 
 |       struct internal_syment *sym = &rawsyms[i].u.syment; | 
 |  | 
 |       switch (sym->n_sclass) | 
 | 	{ | 
 | 	case C_FILE: | 
 | 	  { | 
 | 	    /* New source file announced.  */ | 
 | 	    struct coff_sfile *n = | 
 | 	      (struct coff_sfile *) xmalloc (sizeof (struct coff_sfile)); | 
 |  | 
 | 	    n->section = (struct coff_isection *) xcalloc (sizeof (struct coff_isection), abfd->section_count + 1); | 
 | 	    cur_sfile = n; | 
 | 	    n->name = N(sym); | 
 | 	    n->next = 0; | 
 |  | 
 | 	    if (infile) | 
 | 	      pop_scope (); | 
 | 	    else | 
 | 	      infile = true; | 
 |  | 
 | 	    push_scope (1); | 
 | 	    file_scope = n->scope = top_scope; | 
 |  | 
 | 	    if (head->source_tail) | 
 | 	      head->source_tail->next = n; | 
 | 	    else | 
 | 	      head->source_head = n; | 
 | 	    head->source_tail = n; | 
 | 	    head->nsources++; | 
 | 	    i += sym->n_numaux + 1; | 
 | 	  } | 
 | 	  break; | 
 | 	case C_FCN: | 
 | 	  { | 
 | 	    char *name = N(sym); | 
 |  | 
 | 	    if (name[1] == 'b') | 
 | 	      { | 
 | 		/* Function start.  */ | 
 | 		push_scope (0); | 
 | 		/* PR 17512: file: 0ef7fbaf.  */ | 
 | 		if (last_function_type) | 
 | 		  last_function_type->u.function.code = top_scope; | 
 | 		/* PR 17512: file: 22908266.  */ | 
 | 		if (sym->n_scnum < ofile->nsections && sym->n_scnum >= 0) | 
 | 		  top_scope->sec = ofile->sections + sym->n_scnum; | 
 | 		else | 
 | 		  top_scope->sec = NULL; | 
 | 		top_scope->offset = sym->n_value; | 
 | 	      } | 
 | 	    else | 
 | 	      { | 
 | 		/* PR 17512: file: e92e42e1.  */ | 
 | 		if (top_scope == NULL) | 
 | 		  fatal (_("Function start encountered without a top level scope.")); | 
 | 		top_scope->size = sym->n_value - top_scope->offset + 1; | 
 | 		pop_scope (); | 
 | 	      } | 
 | 	    i += sym->n_numaux + 1; | 
 | 	  } | 
 | 	  break; | 
 |  | 
 | 	case C_BLOCK: | 
 | 	  { | 
 | 	    char *name = N(sym); | 
 |  | 
 | 	    if (name[1] == 'b') | 
 | 	      { | 
 | 		/* Block start.  */ | 
 | 		push_scope (1); | 
 | 		/* PR 17512: file: af7e8e83.  */ | 
 | 		if (sym->n_scnum < ofile->nsections && sym->n_scnum >= 0) | 
 | 		  top_scope->sec = ofile->sections + sym->n_scnum; | 
 | 		else | 
 | 		  top_scope->sec = NULL; | 
 | 		top_scope->offset = sym->n_value; | 
 | 	      } | 
 | 	    else | 
 | 	      { | 
 | 		if (top_scope == NULL) | 
 | 		  fatal (_("Block start encountered without a scope for it.")); | 
 | 		top_scope->size = sym->n_value - top_scope->offset + 1; | 
 | 		pop_scope (); | 
 | 	      } | 
 | 	    i += sym->n_numaux + 1; | 
 | 	  } | 
 | 	  break; | 
 | 	case C_REGPARM: | 
 | 	case C_ARG: | 
 | 	  if (last_function_symbol == NULL) | 
 | 	    fatal (_("Function arguments encountered without a function definition")); | 
 | 	  i = do_define (i, last_function_symbol->type->u.function.parameters); | 
 | 	  break; | 
 | 	case C_MOS: | 
 | 	case C_MOU: | 
 | 	case C_FIELD: | 
 | 	  /* PR 17512: file: 43ab21f4.  */ | 
 | 	  if (last_struct == NULL) | 
 | 	    fatal (_("Structure element encountered without a structure definition")); | 
 | 	  i = do_define (i, last_struct->u.astructdef.elements); | 
 | 	  break; | 
 | 	case C_MOE: | 
 | 	  if (last_enum == NULL) | 
 | 	    fatal (_("Enum element encountered without an enum definition")); | 
 | 	  i = do_define (i, last_enum->u.aenumdef.elements); | 
 | 	  break; | 
 | 	case C_STRTAG: | 
 | 	case C_ENTAG: | 
 | 	case C_UNTAG: | 
 | 	  /* Various definition.  */ | 
 | 	  if (top_scope == NULL) | 
 | 	    fatal (_("Aggregate definition encountered without a scope")); | 
 | 	  i = do_define (i, top_scope); | 
 | 	  break; | 
 | 	case C_EXT: | 
 | 	case C_LABEL: | 
 | 	  if (file_scope == NULL) | 
 | 	    fatal (_("Label definition encountered without a file scope")); | 
 | 	  i = do_define (i, file_scope); | 
 | 	  break; | 
 | 	case C_STAT: | 
 | 	case C_TPDEF: | 
 | 	case C_AUTO: | 
 | 	case C_REG: | 
 | 	  if (top_scope == NULL) | 
 | 	    fatal (_("Variable definition encountered without a scope")); | 
 | 	  i = do_define (i, top_scope); | 
 | 	  break; | 
 | 	case C_EOS: | 
 | 	  i += sym->n_numaux + 1; | 
 | 	  break; | 
 | 	default: | 
 | 	  fatal (_("Unrecognised symbol class: %d"), sym->n_sclass); | 
 | 	} | 
 |     } | 
 |   do_sections_p2 (head); | 
 |   return head; | 
 | } | 
 |  | 
 | struct coff_ofile * | 
 | coff_grok (bfd *inabfd) | 
 | { | 
 |   long storage; | 
 |   struct coff_ofile *p; | 
 |   abfd = inabfd; | 
 |  | 
 |   if (! bfd_family_coff (abfd)) | 
 |     { | 
 |       non_fatal (_("%s: is not a COFF format file"), bfd_get_filename (abfd)); | 
 |       return NULL; | 
 |     } | 
 |  | 
 |   storage = bfd_get_symtab_upper_bound (abfd); | 
 |  | 
 |   if (storage < 0) | 
 |     bfd_fatal (bfd_get_filename (abfd)); | 
 |  | 
 |   syms = (asymbol **) xmalloc (storage); | 
 |   symcount = bfd_canonicalize_symtab (abfd, syms); | 
 |   if (symcount < 0) | 
 |     bfd_fatal (bfd_get_filename (abfd)); | 
 |   rawsyms = obj_raw_syments (abfd); | 
 |   rawcount = obj_raw_syment_count (abfd); | 
 |   tindex = (struct coff_symbol **) (xcalloc (sizeof (struct coff_symbol *), rawcount)); | 
 |  | 
 |   p = doit (); | 
 |   return p; | 
 | } |