Back to index

cell-binutils  2.17cvs20070401
symtab.c
Go to the documentation of this file.
00001 /* symtab.c
00002 
00003    Copyright 1999, 2000, 2001, 2002, 2004 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
00020    02110-1301, USA.  */
00021 
00022 #include "gprof.h"
00023 #include "search_list.h"
00024 #include "source.h"
00025 #include "symtab.h"
00026 #include "cg_arcs.h"
00027 #include "corefile.h"
00028 
00029 static int cmp_addr (const PTR, const PTR);
00030 
00031 Sym_Table symtab;
00032 
00033 
00034 /* Initialize a symbol (so it's empty).  */
00035 
00036 void
00037 sym_init (Sym *sym)
00038 {
00039   memset (sym, 0, sizeof (*sym));
00040 
00041   /* It is not safe to assume that a binary zero corresponds
00042      to a floating-point 0.0, so initialize floats explicitly.  */
00043   sym->hist.time = 0.0;
00044   sym->cg.child_time = 0.0;
00045   sym->cg.prop.fract = 0.0;
00046   sym->cg.prop.self = 0.0;
00047   sym->cg.prop.child = 0.0;
00048 }
00049 
00050 
00051 /* Compare the function entry-point of two symbols and return <0, =0,
00052    or >0 depending on whether the left value is smaller than, equal
00053    to, or greater than the right value.  If two symbols are equal
00054    but one has is_func set and the other doesn't, we make the
00055    non-function symbol one "bigger" so that the function symbol will
00056    survive duplicate removal.  Finally, if both symbols have the
00057    same is_func value, we discriminate against is_static such that
00058    the global symbol survives.  */
00059 
00060 static int
00061 cmp_addr (const PTR lp, const PTR rp)
00062 {
00063   const Sym *left = (const Sym *) lp;
00064   const Sym *right = (const Sym *) rp;
00065 
00066   if (left->addr > right->addr)
00067     return 1;
00068   else if (left->addr < right->addr)
00069     return -1;
00070 
00071   if (left->is_func != right->is_func)
00072     return right->is_func - left->is_func;
00073 
00074   return left->is_static - right->is_static;
00075 }
00076 
00077 
00078 void
00079 symtab_finalize (Sym_Table *tab)
00080 {
00081   Sym *src, *dst;
00082   bfd_vma prev_addr;
00083 
00084   if (!tab->len)
00085     return;
00086 
00087   /* Sort symbol table in order of increasing function addresses.  */
00088   qsort (tab->base, tab->len, sizeof (Sym), cmp_addr);
00089 
00090   /* Remove duplicate entries to speed-up later processing and
00091      set end_addr if its not set yet.  */
00092   prev_addr = tab->base[0].addr + 1;
00093 
00094   for (src = dst = tab->base; src < tab->limit; ++src)
00095     {
00096       if (src->addr == prev_addr)
00097        {
00098          /* If same address, favor global symbol over static one,
00099             then function over line number.  If both symbols are
00100             either static or global and either function or line, check
00101             whether one has name beginning with underscore while
00102             the other doesn't.  In such cases, keep sym without
00103             underscore.  This takes cares of compiler generated
00104             symbols (such as __gnu_compiled, __c89_used, etc.).  */
00105          if ((!src->is_static && dst[-1].is_static)
00106              || ((src->is_static == dst[-1].is_static)
00107                 && ((src->is_func && !dst[-1].is_func)
00108                     || ((src->is_func == dst[-1].is_func)
00109                        && ((src->name[0] != '_' && dst[-1].name[0] == '_')
00110                            || (src->name[0]
00111                               && src->name[1] != '_'
00112                               && dst[-1].name[1] == '_'))))))
00113            {
00114              DBG (AOUTDEBUG | IDDEBUG,
00115                  printf ("[symtab_finalize] favor %s@%c%c over %s@%c%c",
00116                         src->name, src->is_static ? 't' : 'T',
00117                         src->is_func ? 'F' : 'f',
00118                         dst[-1].name, dst[-1].is_static ? 't' : 'T',
00119                         dst[-1].is_func ? 'F' : 'f');
00120                  printf (" (addr=%lx)\n", (unsigned long) src->addr));
00121 
00122              dst[-1] = *src;
00123            }
00124          else
00125            {
00126              DBG (AOUTDEBUG | IDDEBUG,
00127                  printf ("[symtab_finalize] favor %s@%c%c over %s@%c%c",
00128                         dst[-1].name, dst[-1].is_static ? 't' : 'T',
00129                         dst[-1].is_func ? 'F' : 'f',
00130                         src->name, src->is_static ? 't' : 'T',
00131                         src->is_func ? 'F' : 'f');
00132                  printf (" (addr=%lx)\n", (unsigned long) src->addr));
00133            }
00134        }
00135       else
00136        {
00137          if (dst > tab->base && dst[-1].end_addr == 0)
00138            dst[-1].end_addr = src->addr - 1;
00139 
00140          /* Retain sym only if it has a non-empty address range.  */
00141          if (!src->end_addr || src->addr <= src->end_addr)
00142            {
00143              *dst = *src;
00144              dst++;
00145              prev_addr = src->addr;
00146            }
00147        }
00148     }
00149 
00150   if (tab->len > 0 && dst[-1].end_addr == 0)
00151     dst[-1].end_addr
00152       = core_text_sect->vma + bfd_get_section_size (core_text_sect) - 1;
00153 
00154   DBG (AOUTDEBUG | IDDEBUG,
00155        printf ("[symtab_finalize]: removed %d duplicate entries\n",
00156               tab->len - (int) (dst - tab->base)));
00157 
00158   tab->limit = dst;
00159   tab->len = tab->limit - tab->base;
00160 
00161   DBG (AOUTDEBUG | IDDEBUG,
00162        unsigned int j;
00163 
00164        for (j = 0; j < tab->len; ++j)
00165         {
00166           printf ("[symtab_finalize] 0x%lx-0x%lx\t%s\n",
00167                (long) tab->base[j].addr, (long) tab->base[j].end_addr,
00168                tab->base[j].name);
00169         }
00170   );
00171 }
00172 
00173 
00174 #ifdef DEBUG
00175 
00176 Sym *
00177 dbg_sym_lookup (Sym_Table *sym_tab, bfd_vma address)
00178 {
00179   long low, mid, high;
00180   Sym *sym;
00181 
00182   fprintf (stderr, "[dbg_sym_lookup] address 0x%lx\n",
00183           (unsigned long) address);
00184 
00185   sym = sym_tab->base;
00186   for (low = 0, high = sym_tab->len - 1; low != high;)
00187     {
00188       mid = (high + low) >> 1;
00189 
00190       fprintf (stderr, "[dbg_sym_lookup] low=0x%lx, mid=0x%lx, high=0x%lx\n",
00191               low, mid, high);
00192       fprintf (stderr, "[dbg_sym_lookup] sym[m]=0x%lx sym[m + 1]=0x%lx\n",
00193               (unsigned long) sym[mid].addr,
00194               (unsigned long) sym[mid + 1].addr);
00195 
00196       if (sym[mid].addr <= address && sym[mid + 1].addr > address)
00197        return &sym[mid];
00198 
00199       if (sym[mid].addr > address)
00200        high = mid;
00201       else
00202        low = mid + 1;
00203     }
00204 
00205   fprintf (stderr, "[dbg_sym_lookup] binary search fails???\n");
00206 
00207   return 0;
00208 }
00209 
00210 #endif /* DEBUG */
00211 
00212 
00213 /* Look up an address in the symbol-table that is sorted by address.
00214    If address does not hit any symbol, 0 is returned.  */
00215 Sym *
00216 sym_lookup (Sym_Table *sym_tab, bfd_vma address)
00217 {
00218   long low, high;
00219   long mid = -1;
00220   Sym *sym;
00221 #ifdef DEBUG
00222   int probes = 0;
00223 #endif /* DEBUG */
00224 
00225   if (!sym_tab->len)
00226     return 0;
00227 
00228   sym = sym_tab->base;
00229   for (low = 0, high = sym_tab->len - 1; low != high;)
00230     {
00231       DBG (LOOKUPDEBUG, ++probes);
00232       mid = (high + low) / 2;
00233 
00234       if (sym[mid].addr <= address && sym[mid + 1].addr > address)
00235        {
00236          if (address > sym[mid].end_addr)
00237            {
00238              /* Address falls into gap between
00239                sym[mid] and sym[mid + 1].  */
00240              return 0;
00241            }
00242          else
00243            {
00244              DBG (LOOKUPDEBUG,
00245                  printf ("[sym_lookup] %d probes (symtab->len=%u)\n",
00246                         probes, sym_tab->len - 1));
00247              return &sym[mid];
00248            }
00249        }
00250 
00251       if (sym[mid].addr > address)
00252        high = mid;
00253       else
00254        low = mid + 1;
00255     }
00256 
00257   if (sym[mid + 1].addr <= address)
00258     {
00259       if (address > sym[mid + 1].end_addr)
00260        {
00261          /* Address is beyond end of sym[mid + 1].  */
00262          return 0;
00263        }
00264       else
00265        {
00266          DBG (LOOKUPDEBUG, printf ("[sym_lookup] %d (%u) probes, fall off\n",
00267                                 probes, sym_tab->len - 1));
00268          return &sym[mid + 1];
00269        }
00270     }
00271 
00272   return 0;
00273 }