Back to index

cell-binutils  2.17cvs20070401
coffgrok.c
Go to the documentation of this file.
00001 /* coffgrok.c
00002    Copyright 1994, 1995, 1997, 1998, 2000, 2001, 2002, 2003, 2004
00003    Free Software Foundation, Inc.
00004 
00005 This file is part of GNU Binutils.
00006 
00007 This program is free software; you can redistribute it and/or modify
00008 it under the terms of the GNU General Public License as published by
00009 the Free Software Foundation; either version 2 of the License, or
00010 (at your option) any later version.
00011 
00012 This program is distributed in the hope that it will be useful,
00013 but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with this program; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
00020 
00021 /* Written by Steve Chamberlain (sac@cygnus.com)
00022 
00023    This module reads a coff file and builds a really simple type tree
00024    which can be read by other programs.  The first application is a
00025    coff->sysroff converter.  It can be tested with coffdump.c.
00026 
00027 */
00028 
00029 #include "bfd.h"
00030 #include "libiberty.h"
00031 #include "bucomm.h"
00032 
00033 #include "coff/internal.h"
00034 #include "../bfd/libcoff.h"
00035 #include "coffgrok.h"
00036 static int lofile = 1;
00037 static struct coff_scope *top_scope;
00038 static struct coff_scope *file_scope;
00039 static struct coff_ofile *ofile;
00040 
00041 static struct coff_symbol *last_function_symbol;
00042 static struct coff_type *last_function_type;
00043 static struct coff_type *last_struct;
00044 static struct coff_type *last_enum;
00045 static struct coff_sfile *cur_sfile;
00046 
00047 static struct coff_symbol **tindex;
00048 
00049 
00050 static asymbol **syms;
00051 static long symcount;
00052 
00053 #define N(x) ((x)->_n._n_nptr[1])
00054 
00055 static struct coff_ptr_struct *rawsyms;
00056 static int rawcount;
00057 static bfd *abfd;
00058 
00059 #define PTR_SIZE     4
00060 #define SHORT_SIZE   2
00061 #define INT_SIZE     4
00062 #define LONG_SIZE    4
00063 #define FLOAT_SIZE   4
00064 #define DOUBLE_SIZE  8
00065 
00066 #define INDEXOF(p)  ((struct coff_ptr_struct *)(p)-(rawsyms))
00067 
00068 static struct coff_scope *empty_scope (void);
00069 static struct coff_symbol *empty_symbol (void);
00070 static void push_scope (int);
00071 static void pop_scope (void);
00072 static void do_sections_p1 (struct coff_ofile *);
00073 static void do_sections_p2 (struct coff_ofile *);
00074 static struct coff_where *do_where (int);
00075 static struct coff_line *do_lines (int, char *);
00076 static struct coff_type *do_type (int);
00077 static struct coff_visible *do_visible (int);
00078 static int do_define (int, struct coff_scope *);
00079 static struct coff_ofile *doit (void);
00080 
00081 static struct coff_scope *
00082 empty_scope (void)
00083 {
00084   struct coff_scope *l;
00085   l = (struct coff_scope *) (xcalloc (sizeof (struct coff_scope), 1));
00086   return l;
00087 }
00088 
00089 static struct coff_symbol *
00090 empty_symbol (void)
00091 {
00092   return (struct coff_symbol *) (xcalloc (sizeof (struct coff_symbol), 1));
00093 }
00094 
00095 /*int l;*/
00096 static void
00097 push_scope (int link)
00098 {
00099   struct coff_scope *n = empty_scope ();
00100   if (link)
00101     {
00102       if (top_scope)
00103        {
00104          if (top_scope->list_tail)
00105            {
00106              top_scope->list_tail->next = n;
00107            }
00108          else
00109            {
00110              top_scope->list_head = n;
00111            }
00112          top_scope->list_tail = n;
00113        }
00114     }
00115   n->parent = top_scope;
00116 
00117   top_scope = n;
00118 }
00119 
00120 static void
00121 pop_scope (void)
00122 {
00123   top_scope = top_scope->parent;
00124 }
00125 
00126 static void
00127 do_sections_p1 (struct coff_ofile *head)
00128 {
00129   asection *section;
00130   int idx;
00131   struct coff_section *all = (struct coff_section *) (xcalloc (abfd->section_count + 1,
00132                                         sizeof (struct coff_section)));
00133   head->nsections = abfd->section_count + 1;
00134   head->sections = all;
00135 
00136   for (idx = 0, section = abfd->sections; section; section = section->next, idx++)
00137     {
00138       long relsize;
00139       int i = section->target_index;
00140       arelent **relpp;
00141       long relcount;
00142 
00143       relsize = bfd_get_reloc_upper_bound (abfd, section);
00144       if (relsize < 0)
00145        bfd_fatal (bfd_get_filename (abfd));
00146       if (relsize == 0)
00147        continue;
00148       relpp = (arelent **) xmalloc (relsize);
00149       relcount = bfd_canonicalize_reloc (abfd, section, relpp, syms);
00150       if (relcount < 0)
00151        bfd_fatal (bfd_get_filename (abfd));
00152 
00153       head->sections[i].name = (char *) (section->name);
00154       head->sections[i].code = section->flags & SEC_CODE;
00155       head->sections[i].data = section->flags & SEC_DATA;
00156       if (strcmp (section->name, ".bss") == 0)
00157        head->sections[i].data = 1;
00158       head->sections[i].address = section->lma;
00159       head->sections[i].size = bfd_get_section_size (section);
00160       head->sections[i].number = idx;
00161       head->sections[i].nrelocs = section->reloc_count;
00162       head->sections[i].relocs =
00163        (struct coff_reloc *) (xcalloc (section->reloc_count,
00164                                    sizeof (struct coff_reloc)));
00165       head->sections[i].bfd_section = section;
00166     }
00167   head->sections[0].name = "ABSOLUTE";
00168   head->sections[0].code = 0;
00169   head->sections[0].data = 0;
00170   head->sections[0].address = 0;
00171   head->sections[0].size = 0;
00172   head->sections[0].number = 0;
00173 }
00174 
00175 static void
00176 do_sections_p2 (struct coff_ofile *head)
00177 {
00178   asection *section;
00179   for (section = abfd->sections; section; section = section->next)
00180     {
00181       unsigned int j;
00182 
00183       for (j = 0; j < section->reloc_count; j++)
00184        {
00185          int idx;
00186          int i = section->target_index;
00187          struct coff_reloc *r = head->sections[i].relocs + j;
00188          arelent *sr = section->relocation + j;
00189          r->offset = sr->address;
00190          r->addend = sr->addend;
00191          idx = ((coff_symbol_type *) (sr->sym_ptr_ptr[0]))->native - rawsyms;
00192          r->symbol = tindex[idx];
00193        }
00194     }
00195 }
00196 
00197 static struct coff_where *
00198 do_where (int i)
00199 {
00200   struct internal_syment *sym = &rawsyms[i].u.syment;
00201   struct coff_where *where =
00202     (struct coff_where *) (xmalloc (sizeof (struct coff_where)));
00203   where->offset = sym->n_value;
00204 
00205   if (sym->n_scnum == -1)
00206     sym->n_scnum = 0;
00207 
00208   switch (sym->n_sclass)
00209     {
00210     case C_FIELD:
00211       where->where = coff_where_member_of_struct;
00212       where->offset = sym->n_value / 8;
00213       where->bitoffset = sym->n_value % 8;
00214       where->bitsize = rawsyms[i + 1].u.auxent.x_sym.x_misc.x_lnsz.x_size;
00215       break;
00216     case C_MOE:
00217       where->where = coff_where_member_of_enum;
00218       break;
00219     case C_MOS:
00220     case C_MOU:
00221       where->where = coff_where_member_of_struct;
00222       break;
00223     case C_AUTO:
00224     case C_ARG:
00225       where->where = coff_where_stack;
00226       break;
00227     case C_EXT:
00228     case C_STAT:
00229     case C_EXTDEF:
00230     case C_LABEL:
00231       where->where = coff_where_memory;
00232       where->section = &ofile->sections[sym->n_scnum];
00233       break;
00234     case C_REG:
00235     case C_REGPARM:
00236       where->where = coff_where_register;
00237       break;
00238     case C_ENTAG:
00239       where->where = coff_where_entag;
00240       break;
00241     case C_STRTAG:
00242     case C_UNTAG:
00243       where->where = coff_where_strtag;
00244       break;
00245     case C_TPDEF:
00246       where->where = coff_where_typedef;
00247       break;
00248     default:
00249       abort ();
00250       break;
00251     }
00252   return where;
00253 }
00254 
00255 static
00256 struct coff_line *
00257 do_lines (int i, char *name ATTRIBUTE_UNUSED)
00258 {
00259   struct coff_line *res = (struct coff_line *) xcalloc (sizeof (struct coff_line), 1);
00260   asection *s;
00261   unsigned int l;
00262 
00263   /* Find out if this function has any line numbers in the table */
00264   for (s = abfd->sections; s; s = s->next)
00265     {
00266       for (l = 0; l < s->lineno_count; l++)
00267        {
00268          if (s->lineno[l].line_number == 0)
00269            {
00270              if (rawsyms + i == ((coff_symbol_type *) (&(s->lineno[l].u.sym[0])))->native)
00271               {
00272                 /* These lines are for this function - so count them and stick them on */
00273                 int c = 0;
00274                 /* Find the linenumber of the top of the function, since coff linenumbers
00275                    are relative to the start of the function.  */
00276                 int start_line = rawsyms[i + 3].u.auxent.x_sym.x_misc.x_lnsz.x_lnno;
00277 
00278                 l++;
00279                 for (c = 0; s->lineno[l + c + 1].line_number; c++)
00280                   ;
00281 
00282                 /* Add two extra records, one for the prologue and one for the epilogue */
00283                 c += 1;
00284                 res->nlines = c;
00285                 res->lines = (int *) (xcalloc (sizeof (int), c));
00286                 res->addresses = (int *) (xcalloc (sizeof (int), c));
00287                 res->lines[0] = start_line;
00288                 res->addresses[0] = rawsyms[i].u.syment.n_value - s->vma;
00289                 for (c = 0; s->lineno[l + c + 1].line_number; c++)
00290                   {
00291                     res->lines[c + 1] = s->lineno[l + c].line_number + start_line - 1;
00292                     res->addresses[c + 1] = s->lineno[l + c].u.offset;
00293                   }
00294                 return res;
00295               }
00296            }
00297        }
00298     }
00299   return res;
00300 }
00301 
00302 static
00303 struct coff_type *
00304 do_type (int i)
00305 {
00306   struct internal_syment *sym = &rawsyms[i].u.syment;
00307   union internal_auxent *aux = &rawsyms[i + 1].u.auxent;
00308   struct coff_type *res =
00309     (struct coff_type *) xmalloc (sizeof (struct coff_type));
00310   int type = sym->n_type;
00311   int which_dt = 0;
00312   int dimind = 0;
00313 
00314   res->type = coff_basic_type;
00315   res->u.basic = type & 0xf;
00316 
00317   switch (type & 0xf)
00318     {
00319     case T_NULL:
00320     case T_VOID:
00321       if (sym->n_numaux && sym->n_sclass == C_STAT)
00322        {
00323          /* This is probably a section definition */
00324          res->type = coff_secdef_type;
00325          res->size = aux->x_scn.x_scnlen;
00326        }
00327       else
00328        {
00329          if (type == 0)
00330            {
00331              /* Don't know what this is, let's make it a simple int */
00332              res->size = INT_SIZE;
00333              res->u.basic = T_UINT;
00334            }
00335          else
00336            {
00337              /* Else it could be a function or pointer to void */
00338              res->size = 0;
00339            }
00340        }
00341       break;
00342 
00343 
00344       break;
00345     case T_UCHAR:
00346     case T_CHAR:
00347       res->size = 1;
00348       break;
00349     case T_USHORT:
00350     case T_SHORT:
00351       res->size = SHORT_SIZE;
00352       break;
00353     case T_UINT:
00354     case T_INT:
00355       res->size = INT_SIZE;
00356       break;
00357     case T_ULONG:
00358     case T_LONG:
00359       res->size = LONG_SIZE;
00360       break;
00361     case T_FLOAT:
00362       res->size = FLOAT_SIZE;
00363       break;
00364     case T_DOUBLE:
00365       res->size = DOUBLE_SIZE;
00366       break;
00367     case T_STRUCT:
00368     case T_UNION:
00369       if (sym->n_numaux)
00370        {
00371          if (aux->x_sym.x_tagndx.p)
00372            {
00373              /* Referring to a struct defined elsewhere */
00374              res->type = coff_structref_type;
00375              res->u.astructref.ref = tindex[INDEXOF (aux->x_sym.x_tagndx.p)];
00376              res->size = res->u.astructref.ref ?
00377               res->u.astructref.ref->type->size : 0;
00378            }
00379          else
00380            {
00381              /* A definition of a struct */
00382              last_struct = res;
00383              res->type = coff_structdef_type;
00384              res->u.astructdef.elements = empty_scope ();
00385              res->u.astructdef.idx = 0;
00386              res->u.astructdef.isstruct = (type & 0xf) == T_STRUCT;
00387              res->size = aux->x_sym.x_misc.x_lnsz.x_size;
00388            }
00389        }
00390       else
00391        {
00392          /* No auxents - it's anonymous */
00393          res->type = coff_structref_type;
00394          res->u.astructref.ref = 0;
00395          res->size = 0;
00396        }
00397       break;
00398     case T_ENUM:
00399       if (aux->x_sym.x_tagndx.p)
00400        {
00401          /* Referring to a enum defined elsewhere */
00402          res->type = coff_enumref_type;
00403          res->u.aenumref.ref = tindex[INDEXOF (aux->x_sym.x_tagndx.p)];
00404          res->size = res->u.aenumref.ref->type->size;
00405        }
00406       else
00407        {
00408          /* A definition of an enum */
00409          last_enum = res;
00410          res->type = coff_enumdef_type;
00411          res->u.aenumdef.elements = empty_scope ();
00412          res->size = aux->x_sym.x_misc.x_lnsz.x_size;
00413        }
00414       break;
00415     case T_MOE:
00416       break;
00417     }
00418 
00419   for (which_dt = 5; which_dt >= 0; which_dt--)
00420     {
00421       switch ((type >> ((which_dt * 2) + 4)) & 0x3)
00422        {
00423        case 0:
00424          break;
00425        case DT_ARY:
00426          {
00427            struct coff_type *ptr = ((struct coff_type *)
00428                                  xmalloc (sizeof (struct coff_type)));
00429            int els = (dimind < DIMNUM
00430                      ? aux->x_sym.x_fcnary.x_ary.x_dimen[dimind]
00431                      : 0);
00432            ++dimind;
00433            ptr->type = coff_array_type;
00434            ptr->size = els * res->size;
00435            ptr->u.array.dim = els;
00436            ptr->u.array.array_of = res;
00437            res = ptr;
00438            break;
00439          }
00440        case DT_PTR:
00441          {
00442            struct coff_type *ptr =
00443              (struct coff_type *) xmalloc (sizeof (struct coff_type));
00444            ptr->size = PTR_SIZE;
00445            ptr->type = coff_pointer_type;
00446            ptr->u.pointer.points_to = res;
00447            res = ptr;
00448            break;
00449          }
00450        case DT_FCN:
00451          {
00452            struct coff_type *ptr
00453              = (struct coff_type *) xmalloc (sizeof (struct coff_type));
00454            ptr->size = 0;
00455            ptr->type = coff_function_type;
00456            ptr->u.function.function_returns = res;
00457            ptr->u.function.parameters = empty_scope ();
00458            ptr->u.function.lines = do_lines (i, sym->_n._n_nptr[1]);
00459            ptr->u.function.code = 0;
00460            last_function_type = ptr;
00461            res = ptr;
00462            break;
00463          }
00464        }
00465     }
00466   return res;
00467 }
00468 
00469 static struct coff_visible *
00470 do_visible (int i)
00471 {
00472   struct internal_syment *sym = &rawsyms[i].u.syment;
00473   struct coff_visible *visible =
00474     (struct coff_visible *) (xmalloc (sizeof (struct coff_visible)));
00475   enum coff_vis_type t;
00476   switch (sym->n_sclass)
00477     {
00478     case C_MOS:
00479     case C_MOU:
00480     case C_FIELD:
00481       t = coff_vis_member_of_struct;
00482       break;
00483     case C_MOE:
00484       t = coff_vis_member_of_enum;
00485       break;
00486 
00487     case C_REGPARM:
00488       t = coff_vis_regparam;
00489       break;
00490 
00491     case C_REG:
00492       t = coff_vis_register;
00493       break;
00494     case C_STRTAG:
00495     case C_UNTAG:
00496     case C_ENTAG:
00497     case C_TPDEF:
00498       t = coff_vis_tag;
00499       break;
00500     case C_AUTOARG:
00501     case C_ARG:
00502       t = coff_vis_autoparam;
00503       break;
00504     case C_AUTO:
00505 
00506 
00507       t = coff_vis_auto;
00508       break;
00509     case C_LABEL:
00510     case C_STAT:
00511       t = coff_vis_int_def;
00512       break;
00513     case C_EXT:
00514       if (sym->n_scnum == N_UNDEF)
00515        {
00516          if (sym->n_value)
00517            t = coff_vis_common;
00518          else
00519            t = coff_vis_ext_ref;
00520        }
00521       else
00522        t = coff_vis_ext_def;
00523       break;
00524     default:
00525       abort ();
00526       break;
00527 
00528     }
00529   visible->type = t;
00530   return visible;
00531 }
00532 
00533 static int
00534 do_define (int i, struct coff_scope *b)
00535 {
00536   static int symbol_index;
00537   struct internal_syment *sym = &rawsyms[i].u.syment;
00538 
00539   /* Define a symbol and attach to block b */
00540   struct coff_symbol *s = empty_symbol ();
00541 
00542   s->number = ++symbol_index;
00543   s->name = sym->_n._n_nptr[1];
00544   s->sfile = cur_sfile;
00545   /* Glue onto the ofile list */
00546   if (lofile >= 0)
00547     {
00548       if (ofile->symbol_list_tail)
00549        ofile->symbol_list_tail->next_in_ofile_list = s;
00550       else
00551        ofile->symbol_list_head = s;
00552       ofile->symbol_list_tail = s;
00553       /* And the block list */
00554     }
00555   if (b->vars_tail)
00556     b->vars_tail->next = s;
00557   else
00558     b->vars_head = s;
00559 
00560   b->vars_tail = s;
00561   b->nvars++;
00562   s->type = do_type (i);
00563   s->where = do_where (i);
00564   s->visible = do_visible (i);
00565 
00566   tindex[i] = s;
00567 
00568   /* We remember the lowest address in each section for each source file */
00569 
00570   if (s->where->where == coff_where_memory
00571       && s->type->type == coff_secdef_type)
00572     {
00573       struct coff_isection *is = cur_sfile->section + s->where->section->number;
00574 
00575       if (!is->init)
00576        {
00577          is->low = s->where->offset;
00578          is->high = s->where->offset + s->type->size;
00579          is->init = 1;
00580          is->parent = s->where->section;
00581        }
00582 
00583     }
00584 
00585   if (s->type->type == coff_function_type)
00586     last_function_symbol = s;
00587 
00588   return i + sym->n_numaux + 1;
00589 }
00590 
00591 
00592 static
00593 struct coff_ofile *
00594 doit (void)
00595 {
00596   int i;
00597   int infile = 0;
00598   struct coff_ofile *head =
00599     (struct coff_ofile *) xmalloc (sizeof (struct coff_ofile));
00600   ofile = head;
00601   head->source_head = 0;
00602   head->source_tail = 0;
00603   head->nsources = 0;
00604   head->symbol_list_tail = 0;
00605   head->symbol_list_head = 0;
00606   do_sections_p1 (head);
00607   push_scope (1);
00608 
00609   for (i = 0; i < rawcount;)
00610     {
00611       struct internal_syment *sym = &rawsyms[i].u.syment;
00612       switch (sym->n_sclass)
00613        {
00614        case C_FILE:
00615          {
00616            /* new source file announced */
00617            struct coff_sfile *n =
00618              (struct coff_sfile *) xmalloc (sizeof (struct coff_sfile));
00619            n->section = (struct coff_isection *) xcalloc (sizeof (struct coff_isection), abfd->section_count + 1);
00620            cur_sfile = n;
00621            n->name = sym->_n._n_nptr[1];
00622            n->next = 0;
00623 
00624            if (infile)
00625              {
00626               pop_scope ();
00627              }
00628            infile = 1;
00629            push_scope (1);
00630            file_scope = n->scope = top_scope;
00631 
00632            if (head->source_tail)
00633              head->source_tail->next = n;
00634            else
00635              head->source_head = n;
00636            head->source_tail = n;
00637            head->nsources++;
00638            i += sym->n_numaux + 1;
00639          }
00640          break;
00641        case C_FCN:
00642          {
00643            char *name = sym->_n._n_nptr[1];
00644            if (name[1] == 'b')
00645              {
00646               /* Function start */
00647               push_scope (0);
00648               last_function_type->u.function.code = top_scope;
00649               top_scope->sec = ofile->sections + sym->n_scnum;
00650               top_scope->offset = sym->n_value;
00651              }
00652            else
00653              {
00654               top_scope->size = sym->n_value - top_scope->offset + 1;
00655               pop_scope ();
00656 
00657              }
00658            i += sym->n_numaux + 1;
00659          }
00660          break;
00661 
00662        case C_BLOCK:
00663          {
00664            char *name = sym->_n._n_nptr[1];
00665            if (name[1] == 'b')
00666              {
00667               /* Block start */
00668               push_scope (1);
00669               top_scope->sec = ofile->sections + sym->n_scnum;
00670               top_scope->offset = sym->n_value;
00671 
00672              }
00673            else
00674              {
00675               top_scope->size = sym->n_value - top_scope->offset + 1;
00676               pop_scope ();
00677              }
00678            i += sym->n_numaux + 1;
00679          }
00680          break;
00681        case C_REGPARM:
00682        case C_ARG:
00683          i = do_define (i, last_function_symbol->type->u.function.parameters);
00684          break;
00685        case C_MOS:
00686        case C_MOU:
00687        case C_FIELD:
00688          i = do_define (i, last_struct->u.astructdef.elements);
00689          break;
00690        case C_MOE:
00691          i = do_define (i, last_enum->u.aenumdef.elements);
00692          break;
00693        case C_STRTAG:
00694        case C_ENTAG:
00695        case C_UNTAG:
00696          /* Various definition */
00697          i = do_define (i, top_scope);
00698          break;
00699        case C_EXT:
00700        case C_LABEL:
00701          i = do_define (i, file_scope);
00702          break;
00703        case C_STAT:
00704        case C_TPDEF:
00705        case C_AUTO:
00706        case C_REG:
00707          i = do_define (i, top_scope);
00708          break;
00709        default:
00710          abort ();
00711        case C_EOS:
00712          i += sym->n_numaux + 1;
00713          break;
00714        }
00715     }
00716   do_sections_p2 (head);
00717   return head;
00718 }
00719 
00720 struct coff_ofile *
00721 coff_grok (bfd *inabfd)
00722 {
00723   long storage;
00724   struct coff_ofile *p;
00725   abfd = inabfd;
00726   storage = bfd_get_symtab_upper_bound (abfd);
00727 
00728   if (storage < 0)
00729     bfd_fatal (abfd->filename);
00730 
00731   syms = (asymbol **) xmalloc (storage);
00732   symcount = bfd_canonicalize_symtab (abfd, syms);
00733   if (symcount < 0)
00734     bfd_fatal (abfd->filename);
00735   rawsyms = obj_raw_syments (abfd);
00736   rawcount = obj_raw_syment_count (abfd);;
00737   tindex = (struct coff_symbol **) (xcalloc (sizeof (struct coff_symbol *), rawcount));
00738 
00739   p = doit ();
00740   return p;
00741 }