|  | /* coffgrok.c | 
|  | Copyright (C) 1994-2025 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 (1, sizeof (struct coff_scope))); | 
|  | } | 
|  |  | 
|  | static struct coff_symbol * | 
|  | empty_symbol (void) | 
|  | { | 
|  | return (struct coff_symbol *) (xcalloc (1, sizeof (struct coff_symbol))); | 
|  | } | 
|  |  | 
|  | 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 (1, sizeof (struct coff_line)); | 
|  | 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 (c, sizeof (int))); | 
|  | res->addresses = (int *) (xcalloc (c, sizeof (int))); | 
|  | 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; | 
|  | combined_entry_type *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]; | 
|  |  | 
|  | 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->u.auxent.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->fix_tag) | 
|  | { | 
|  | unsigned int idx = INDEXOF (aux->u.auxent.x_sym.x_tagndx.p); | 
|  |  | 
|  | /* 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->u.auxent.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->fix_tag) | 
|  | { | 
|  | unsigned int idx = INDEXOF (aux->u.auxent.x_sym.x_tagndx.p); | 
|  |  | 
|  | /* 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->u.auxent.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->u.auxent.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 (abfd->section_count + 1, sizeof (struct coff_isection)); | 
|  | 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 (rawcount, | 
|  | sizeof (struct coff_symbol *))); | 
|  |  | 
|  | p = doit (); | 
|  | return p; | 
|  | } |